1. Introduction and Aims

We have quality-controlled the 10X data and the SS2 data and now are left with the following objects:

10X 5K data - pb_sex_filtered

10X 30K data - pb_30k_sex_filtered

SS2 mutant data - ss2_mutants_final

2. Read in the data

Load/Install the Required Packages

[1] "patchwork is loaded correctly"
[1] "viridis is loaded correctly"
[1] "Seurat is loaded correctly"
Loading required package: cowplot

Attaching package: ‘cowplot’

The following object is masked from ‘package:patchwork’:

    align_plots
[1] "cowplot is loaded correctly"
Loading required package: gridExtra
[1] "gridExtra is loaded correctly"
Loading required package: grid
[1] "grid is loaded correctly"
Loading required package: Hmisc
Loading required package: lattice
Loading required package: survival
Loading required package: Formula
Loading required package: ggplot2

Attaching package: ‘Hmisc’

The following object is masked from ‘package:Seurat’:

    Key

The following objects are masked from ‘package:base’:

    format.pval, units
[1] "Hmisc is loaded correctly"
Loading required package: reshape2
[1] "reshape2 is loaded correctly"
Loading required package: dplyr

Attaching package: ‘dplyr’

The following objects are masked from ‘package:Hmisc’:

    src, summarize

The following object is masked from ‘package:gridExtra’:

    combine

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
[1] "dplyr is loaded correctly"
Loading required package: Nebulosa
[1] "Nebulosa is loaded correctly"

Read in the Data

screen hits

## EDIT - change this to the excel table once we have it finalized for the screen
screen_hits <- c("PBANKA-0516300",
"PBANKA-1217700",
"PBANKA-0409100",
"PBANKA-1034300",
"PBANKA-1437500",
"PBANKA-0827500",
"PBANKA-0824300",
"PBANKA-1426900",
"PBANKA-0105300",
"PBANKA-0921100",
"PBANKA-1002400",
"PBANKA-0829400",
"PBANKA-1347200",
"PBANKA-0828000",
"PBANKA-0902300",
"PBANKA-1418100",
"PBANKA-1435200",
"PBANKA-1454800",
"PBANKA-0712300",
"PBANKA-0410500",
"PBANKA-1144800",
"PBANKA-1231600",
"PBANKA-0503200",
"PBANKA-0308900",
"PBANKA-1214700",
"PBANKA-0709900",
"PBANKA-0311900",
"PBANKA-0716500",
"PBANKA-1447900",
"PBANKA-0102200",
"PBANKA-0713500",
"PBANKA-0102400",
"PBANKA-1302700",
"PBANKA-1235900",
"PBANKA-0401100",
"PBANKA-0413400",
"PBANKA-1126900",
"PBANKA-1425900",
"PBANKA-0418300",
"PBANKA-1464600",
"PBANKA-0806000")

load in datasets

## load the 10X dataset
pb_sex_filtered <- readRDS("../data_to_export/pb_sex_filtered.RDS")
## load the SS2 dataset
ss2_mutants_final <- readRDS("../data_to_export/ss2_mutants_final.RDS")

## inspect
paste("10x dataset")
[1] "10x dataset"
pb_sex_filtered
An object of class Seurat 
5098 features across 6191 samples within 1 assay 
Active assay: RNA (5098 features, 2000 variable features)
 2 dimensional reductions calculated: pca, umap
paste("Smart-seq2 dataset")
[1] "Smart-seq2 dataset"
ss2_mutants_final
An object of class Seurat 
5245 features across 2717 samples within 1 assay 
Active assay: RNA (5245 features, 2000 variable features)
 2 dimensional reductions calculated: pca, umap
paste("The composition of the Smart-seq2 dataset is:")
[1] "The composition of the Smart-seq2 dataset is:"
table(ss2_mutants_final@meta.data$genotype)

Mutant     WT 
  2028    689 

3. Merging the Smart-seq2 and 10X Data

Prepare data

## extract 10x data
tenx_5k_counts <- as.matrix(pb_sex_filtered@assays$RNA@counts)
tenx_5k_pheno <- pb_sex_filtered@meta.data

## Create fresh object
tenx_5k_counts_to_integrate <- CreateSeuratObject(counts = tenx_5k_counts, meta.data = tenx_5k_pheno, min.cells = 0, min.features = 0, project = "GCSKO")
Invalid name supplied, making object name syntactically valid. New object name is orig.identnCount_RNAnFeature_RNAexperimentRNA_snn_res.1seurat_clusterspANN_0.25_0.01_440DF.classifications_0.25_0.01_440Prediction.Spearman.r.Spearman.Prediction.Pearsons.r.Pearsons.Prediction.Spearman._Kasiar.Spearman._KasiaPrediction.Pearson._Kasiar.Pearson._KasiaRNA_snn_res.2RNA_snn_res.3; see ?make.names for more details on syntax validity
## add experiment meta data
tenx_5k_counts_to_integrate@meta.data$experiment <- "tenx_5k"

## inspect
tenx_5k_counts_to_integrate
An object of class Seurat 
5098 features across 6191 samples within 1 assay 
Active assay: RNA (5098 features, 0 variable features)

We need to make sure the mutant data is compatible with the 10X data. the 10X data has fewer genes represented so we need to find the intersect of the two before integration.

## extract SS2 data 
mutant_counts_for_integration <- as.matrix(ss2_mutants_final@assays$RNA@counts)
mutant_pheno_for_integration <- ss2_mutants_final@meta.data

## change counts so the :rRNA and :tRNA are not there:
rownames(mutant_counts_for_integration) <- gsub(":ncRNA", "", gsub(":rRNA", "", gsub(":tRNA", "", rownames(mutant_counts_for_integration))))

## change the gene names so that they are - rather than _:
rownames(mutant_counts_for_integration) <- gsub("_", "-", rownames(mutant_counts_for_integration))

## calculate how many of the genes overlap - 10x does start out with 5098 vs 5245
genes_in_tenx_dataset <- intersect(rownames(tenx_5k_counts), rownames(mutant_counts_for_integration))
## print number of genes that overlap
dim(mutant_counts_for_integration)
[1] 5245 2717
## subset the mutant counts to contain only 10x genes
mutant_counts_for_integration <- mutant_counts_for_integration[which(rownames(mutant_counts_for_integration) %in% genes_in_tenx_dataset), ]
## print result of genes that overlap
dim(mutant_counts_for_integration)
[1] 5018 2717
## make Seurat object:
GCSKO_mutants <- CreateSeuratObject(counts = mutant_counts_for_integration, meta.data = mutant_pheno_for_integration, min.cells = 0, min.features = 0, project = "GCSKO")

## add experiment meta data
GCSKO_mutants@meta.data$experiment <- "mutants"

## inspect
GCSKO_mutants
An object of class Seurat 
5018 features across 2717 samples within 1 assay 
Active assay: RNA (5018 features, 0 variable features)
## double check that this is the same number of genes
## subset counts so that only genes represented in the other two objects are there:
length(intersect(rownames(tenx_5k_counts), rownames(mutant_counts_for_integration)))
[1] 5018

create list and normalise:

## make list
tenx.mutant.list <- list(tenx_5k_counts_to_integrate, GCSKO_mutants)

## prepare data
for (i in 1:length(tenx.mutant.list)) {
    tenx.mutant.list[[i]] <- NormalizeData(tenx.mutant.list[[i]], verbose = FALSE)
    tenx.mutant.list[[i]] <- FindVariableFeatures(tenx.mutant.list[[i]], selection.method = "vst", 
        nfeatures = 2000, verbose = FALSE)
}

Integrate objects

## Find anchors
tenx.mutant.anchors <- FindIntegrationAnchors(object.list = tenx.mutant.list, dims = 1:21, verbose = FALSE)
UNRELIABLE VALUE: Future (‘future_lapply-1’) unexpectedly generated random numbers without specifying argument '[future.]seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify argument '[future.]seed', e.g. 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced via the L'Ecuyer-CMRG method. To disable this check, use [future].seed=NULL, or set option 'future.rng.onMisuse' to "ignore".
## Integrate data
tenx.mutant.integrated <- IntegrateData(anchorset = tenx.mutant.anchors, dims = 1:21, verbose = FALSE, features.to.integrate = genes_in_tenx_dataset)
Adding a command log without an assay associated with it

4. Dimensionality reduction

PCA

## Make the default assay integrated
DefaultAssay(tenx.mutant.integrated) <- "integrated"

## Run the standard workflow for visualization and clustering
tenx.mutant.integrated <- ScaleData(tenx.mutant.integrated, verbose = FALSE)
tenx.mutant.integrated <- RunPCA(tenx.mutant.integrated, npcs = 30, verbose = FALSE)

## inspect PCs
ElbowPlot(tenx.mutant.integrated, ndims = 30, reduction = "pca")

UMAP

Initial UMAP

Run inital UMAP

## Run UMAP
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, n.neighbors = 50, seed.use = 1234, min.dist = 0.5, repulsion.strength = 0.05)
The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session23:37:23 UMAP embedding parameters a = 0.583 b = 1.334
23:37:23 Read 8908 rows and found 8 numeric columns
23:37:23 Using Annoy for neighbor search, n_neighbors = 50
23:37:23 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
23:37:25 Writing NN index file to temp file /var/folders/7t/kvh8b3952x9_4b3r74r1kstc000glh/T//RtmpkxWyey/filed4b463f0bca
23:37:26 Searching Annoy index using 1 thread, search_k = 5000
23:37:32 Annoy recall = 100%
23:37:32 Commencing smooth kNN distance calibration using 1 thread
23:37:35 Initializing from normalized Laplacian + noise
23:37:36 Commencing optimization for 500 epochs, with 583548 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
23:37:53 Optimization finished

See distribution by: altogether, experiment, and mutant ID

## Plot
DimPlot(tenx.mutant.integrated, reduction = "umap", pt.size = 0.01)

DimPlot(tenx.mutant.integrated, reduction = "umap", split.by = "experiment", pt.size = 0.01)

DimPlot(tenx.mutant.integrated, reduction = "umap", group.by = "identity_updated", label = TRUE, repel = TRUE, pt.size = 0.01)
Using `as.character()` on a quosure is deprecated as of rlang 0.3.0.
Please use `as_label()` or `as_name()` instead.
This warning is displayed once per session.

Optimised UMAP

After optimisation, the following UMAP can be calculated:

## Run optimised UMAP
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)
23:43:26 UMAP embedding parameters a = 0.7669 b = 1.223
23:43:26 Read 8908 rows and found 10 numeric columns
23:43:26 Using Annoy for neighbor search, n_neighbors = 150
23:43:26 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
23:43:28 Writing NN index file to temp file /var/folders/7t/kvh8b3952x9_4b3r74r1kstc000glh/T//RtmpkxWyey/filed4b551f1ecd
23:43:28 Searching Annoy index using 1 thread, search_k = 15000
23:43:41 Annoy recall = 100%
23:43:42 Commencing smooth kNN distance calibration using 1 thread
23:43:42 8908 smooth knn distance failures
23:43:45 Initializing from normalized Laplacian + noise
23:43:46 Commencing optimization for 500 epochs, with 1813006 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
23:48:35 Optimization finished
## plot
dp1 <- DimPlot(tenx.mutant.integrated, label = TRUE, repel = FALSE, pt.size = 0.05, dims = c(2,1), group.by = "experiment") + 
  ## fix the axis
  coord_fixed() + 
  ## reverse the scale
  #scale_x_reverse() + 
  scale_y_reverse()

## view
dp1

Now store these reversed embeddings in a new slot

## extract the cell embeddings from the UMAP
mds <- as.data.frame(tenx.mutant.integrated@reductions$umap@cell.embeddings)

## change the coordinates of UMAP 1 so they are reversed
mds$UMAP_1 <- -mds$UMAP_1

## change names of the cols 
colnames(mds) <- paste0("DIM_UMAP_", 1:2)

## make into a matrix so that it can be saved in Seurat
mds <- as.matrix(mds)

## store this optimsed UMAP in a custom dim slot
tenx.mutant.integrated[["DIM_UMAP"]] <- CreateDimReducObject(embeddings = mds, key = "DIM_UMAP_", assay = DefaultAssay(tenx.mutant.integrated))
Keys should be one or more alphanumeric characters followed by an underscore, setting key from DIM_UMAP_ to DIMUMAP_All keys should be one or more alphanumeric characters followed by an underscore '_', setting key to DIMUMAP_
## check
DimPlot(tenx.mutant.integrated, label = TRUE, repel = FALSE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP") + coord_fixed()

5. Clustering

Generate clusters

Recluster dataset now that it is integrated. We will cluster with a number of resolutions to begin with to see how this affects the number and nature of the clusters.

## copy old clusters
tenx.mutant.integrated <- AddMetaData(tenx.mutant.integrated, tenx.mutant.integrated@meta.data$RNA_snn_res.1, col.name = "pre_integration_clusters")

## generate new clusters at low resolution
## 1
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
Computing nearest neighbor graph
Computing SNN
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 8908
Number of edges: 319840

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8616
Number of communities: 21
Elapsed time: 1 seconds
## generate new clusters at low resolution
## 1.2
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
Computing nearest neighbor graph
Computing SNN
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1.2, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 8908
Number of edges: 319840

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8494
Number of communities: 22
Elapsed time: 1 seconds
## generate new clusters at low resolution
## 1.5
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
Computing nearest neighbor graph
Computing SNN
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1.5, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 8908
Number of edges: 319840

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8315
Number of communities: 24
Elapsed time: 1 seconds
## generate new clusters at mid resolution
## 2
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
Computing nearest neighbor graph
Computing SNN
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 2, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 8908
Number of edges: 319840

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8052
Number of communities: 29
Elapsed time: 1 seconds
## generate new clusters at high resolution
## 4
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
Computing nearest neighbor graph
Computing SNN
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 4, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 8908
Number of edges: 319840

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.7355
Number of communities: 46
Elapsed time: 2 seconds
## print identities
#head(Idents(tenx.mutant.integrated), 10)

Inspect clusters at different resolutions

resolution = 1

View

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "integrated_snn_res.1") + coord_fixed() 

Make individual plots highlighting where cells in each cluster fall

plot

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]]

resolution = 1.2

View

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "integrated_snn_res.1.2") + coord_fixed() 

Make individual plots highlighting where cells in each cluster fall

[1] 22

plot

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]]

resolution = 1.5

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "integrated_snn_res.1.5") + coord_fixed() 

Make individual plots highlighting where cells in each cluster fall

[1] 24
## 1.5 resolution
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] #+ list_UMAPs_by_cluster[[25]]

resolution = 2

View

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "integrated_snn_res.2") + coord_fixed() 

Make individual plots highlighting where cells in each cluster fall

[1] 29

plot

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]] + list_UMAPs_by_cluster[[27]] + list_UMAPs_by_cluster[[28]] + list_UMAPs_by_cluster[[29]]# + list_UMAPs_by_cluster[[30]] + list_UMAPs_by_cluster[[31]]

8 vs 11 on resolution 2 already looks pretty cool:

early.sex.de.markers.screen.hits <- early.sex.de.markers[rownames(early.sex.de.markers) %in% c(screen_hits,"PBANKA-1437500"), ]
early.sex.de.markers.screen.hits

look at them across the dataset

DotPlot(tenx.mutant.integrated, features = rownames(early.sex.de.markers[1:10,])) + RotatedAxis()

DotPlot(tenx.mutant.integrated, features = screen_hits) + RotatedAxis()

```r
## find all markers
#all.markers <- FindAllMarkers(tenx.mutant.integrated, only.pos = FALSE, min.pct = 0.25, logfc.threshold = 0.25)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuI3RvcF90d28gPC0gYWxsLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMiwgd3QgPSBhdmdfbG9nRkMpXG50b3BfdHdvXG5gYGBcbmBgYCJ9 -->

```r
```r
#top_two <- all.markers %>% group_by(cluster) %>% top_n(n = 2, wt = avg_logFC)
top_two

<!-- rnb-source-end -->

<!-- rnb-frame-begin eyJtZXRhZGF0YSI6eyJjbGFzc2VzIjpbImdyb3VwZWRfZGYiLCJ0YmxfZGYiLCJ0YmwiLCJkYXRhLmZyYW1lIl0sIm5yb3ciOjYyLCJuY29sIjo3fSwicmRmIjoiSDRzSUFBQUFBQUFBQTZWV0N6aVUyUnNmdzJDSVZMb2hoTkRGTk4vM3pWVnh2bXpZc2tRWHFlMUNRbW9hZGhxNjdVNjZhYmNidXlWdFc5dUt0dndycWExYy9tMGJRbUdKdEpHVk80V00wRVdGL1dhYzczdithNzU5bm4yZS96elBiK1k5NTd6bnZmemVkODQ1aStjSFlBWUJCZ3dHUTV1aHcyQXl0Rm1FeUdBdFcrcmhKR0l3ZEpqRVFJdFlZS3QrdHhGSzR3aEJqNEF4QVZjMEphNnBoTVdLdzN4NDFsa3Q0enl4K205M0sxN05tdzBjNi9vOEFnUW5YWk84dWx2YnFxYTROdW11Mk4zSzkzYTY4OFhZRkorenptSit5cHAweHc0cFk4VEhMdi9zODVLZDQweWR0czQ4bWc1TzNwLzdzRG0ydDNadHZXdDkrNXNDKy9nblZnL1RGUjZ4dTNaelRpWitzcWhFRVNWZWNPN0lGeE9UdHdFOTJZenVIMG8zb0NzVGxrejVJM0F5bGxaNEt6TjlSOVNrZ3Y3emNiVVBmcktzcUV2WTFYaG10WkZwWXU3eDNIYTVTUzNENXRIRzFmMU9PU2tzenF2REI1d2V4eVY2SHQwak5Pblp0RzJOWkd5eHFVbU9MQ2toUDBrd3Z5d2N1YmIycm92dWQwOStGWWF6N1crMEt4cXFlY29aV1FkNkttMDhqcHB0dXh4cE55Y3IyWHhId2F4WksrMFBtdnM1TmtwV0g2NjF6Q3orVVNnODJ3d0VtVnA2RlFWY0VHYTRlOGFBbDdlenJFeDVPVFVxWlU1R3ZrSm1hempOeWVhZGhQVzJxQWVkY05Bb1k1Ly9OeHl6STg5UDNCcTNuaFB3OFBuRVRJOEI2MXhicDhuTDYwOU15OG5mYnlHSXUySWJGemw5d2FIUHZPeE1oMmFORDNRY2RKandDRXRxM0dub2NPelZxZDZxcGYwT2N5eHZKNmFGZGpzY1B4aXp6Y2JYeEhGRmM0L1ZIdzc3Wm5qN3B0bHdOaHl6WDlEZGc5WUVNV2VDclBJckZsYzJpSll0Q3RqZmlEREZrYTV2SXhsZlovS2pxbmJYQm1zbDhoVmI1OGQ2eG12eCt3U2Q3ais0QWZINE5INnkrWVlvc3U2Z05hbHExR0xuS3REZUZESzRlcWtCK0RCK2pjMjdlMi9CRy90NmhmYjlRNkRYTUxveXE5b0Z2RHJmbkI4YXpnU2QzM1U3VEhyY0NUcVIwaC9Cc3V1NGZsSFpmZVZsVStMMysyalFoQVBsMVpEVXJ3dTZ3U3VoNTBMZGMvcWdQWHZJTHRUdUlIaVpuVzBlY1RNU1o2NWY4ZlBPckhhY0ViaHd4c0RhVU5EcjUxR3dxY0lYOUxCOXdtM2FXMEdIcDdKd2JlSkY4UElyYlMxOTNSaWNjYUwzNHJGN0g4QUhOOU5QKzZiK2lSc0VaMHlXWjVqamVrV3BmcmtMKzhBclAxM3Bxb2tYZ2ZMWUY3NDdJMWZoK2xmbnUxdStMOFgxSTk1MHR0ZDVnMTVKY2V2bmNiNmdmNEp0L0toQ09YZ2R5bDRxK3ZnZXZGNHdzZm45NFptNDBUYW1nV0p6REc1WTVMY2JOTGpqbzMrYWJUU2xjdyt1ZDBLOHZFSitCM1M0YjVKMFpLNENMeElEbzNWYVNrRDMzT3dWd1NkK0JkMTZSMjR5SGo0SEgrK2MyYnZ2NkNFd2xGSCtNY0x6THE0ZDMxNW44QzRhWnk2Zkxpd3UveExYdS9Tc3E3Yi9EcTdqbW5lamdaV0ttNXpGUWh2aUxmRXg3ZDc4clNmemNKMVJuTit6T2hnNHM4LzlmTUVpWFh6TTRtV1BCM0t1NFdPT0ptU2tMeEhnNDY0TjdwMHhtNDJiOUxDZlhYV2JoYlBxRG1HZlczdmd6RjlPTDkvZVlRQUd2OTZaYmF6Tng1bDJUKzdZbmJFR0g4cTJsbm12YUFhRHhkaUM3TWtmY1cxTzdUN1oxQW00MWkzRmR2YTBXS3J1YmZMYkd4WDlOYURsZTlYbkZHaEtNOTNSNEprR1NsNSt1MEdXUGhYVTJEeHNDWnozRFNqK0pHRzNybDB0YUQ4d2t6bHFRVFpvVUMrNGdlN2gvem4xcTRUNzIxMGlrNThZdUlDSGZoMzdMVE1YZ3hwaVFNeUFGd0VtNjd3cmVrRHJxOVFQYlpKRG9QbVF5dkEwVUtkZU5nQ2QwRTdMTjBLdmdndmRRRWtvRVJxZ0syNlY0K3ZjT01xK1VoM09iS0FPMHpvZktOVnF1aHJ4MU1NOEtyd3JWQjZwZVhMZlNIMHFEeGh2YWVLUlJYVnoxb01ITU45bWZjVCt4YmJIb0FYbThaSVlWUTcwZ1k0ejE1Mk0vWFZBSi9UWHVkTGlzajdpQUpRRkY1VEVFbENxYVZ1ajZRZXUvMU1jL3hnZjVLRXJVMDB3NklMNUtZa0JNZk5QKzZpNms3dzNxY1BpZ3dhVkZiOU9VRVdRdk1yeERhaUQ5c2x4bzdvTmhPQlBtRC9aSDZYK09wT095VzlUL3B0Z25xWFI5MitJQTB4QW5acStsYUJpMkEyMXZ3bkcyUWo3b0tIM2xudFNVUTU0ckRhekdWU3BkcS96QVpXUXg5THFDYXJPQTQ5VjRiek9BOCtJNHB1ZHZRTWExRzFnRHZJdzlRZmNoL0hlUDZacTdQZGdtRjVqVUsxU00vc0pWS3JiM1Jia3E3THhLZ1JsaEJFaVZGQU0renh2ckZSVmNWRDNwVHBCOEFUVzlUSFVmNlpPYXgwb2huVXJoMzFRUkNSSGJBR2wvZXBHQVZtd1gvS1d2RldGRG5KaC9yL0R2aVA5RlE0bkJ1NnAwOWtLOG1FK1pIeWszbDNWc09BaXVBZjVxS29jSUJnN1I4WDN1NXJtS2FBYzVsbEE4bE4wZCs5WTZVbXk3bGc0dDFCVy9yT1NOemJHeCt0WlVoMHY1VE0zZDd0Rk8wSFg5dFhucnBRM2doQnVLcVBodmkyNDRITWhMTy9DS002ZTg4bHozRGU4RUwvZnE0aUpuN3A1NVAwKzdhQkM3OWdlVDhDWnUrNTIycVVYaDEyT1gzdGJ1Y2MwQWFSa1BmMHVaZ2l4UGk0VC9XSy92Mi8yR3V0RmY1eHJsVGlQRHJ0MzRISkNDaWpKY3FuUnFiK0RXWCthMkgrci9sZWU3T25OTTFxbnRDY2ZucFlvRDV4Z2E1Vm9OVDIyaE1FMnFuYmVsTE5yNFk0eFNYbm5sMWtucG5QMm40NnZQbmZwQWVmVVJ2Wk45aHZQTWJmaVgvaGZzWTgxcll3ZEhNMjNjQkd5RmQrRG1NNHVsK0lMNTQvTVpobzdiRDliZUMwaWEvdk1YWjZ6YW0yK1NqZDNkY1liZ3k5OVpvR0g3dTFxZi9kZmkvR3NXK3VaNXRldEZJRmJib1RzMXpqUDVnZ05CNGJhekg2Yis1WFZFdjNqbkFOT2JTNkovbVhYdGRDYTB3MUd2VEg3T1BYempmVEx3M0ptVzRaMitZK2UrbTVxckNqQWV0YW4rK3ozNS8rQXBpKy9aN2RrWHZQQ1ZjbVg3YXF6TElLdWRva2NhdDRvcG1MakJ4d0RwTFh5RDIxbWpvelRlUzJwKzZTT0syWTRKVHV4L2FkYlpabGI0N2Vuenh6VDkrRS92a1lSRHFNTFN6T09Nak5uYVVjd2YzdHEvVTVzWnI3MEVXdk9RbWVzemJieHhBV0Z3RGx2emFTcWpZOEVicW5TMUppYnJZTE12QWU4Z21YNjRxZHhoNk42dGxRUjd6c2pWZDBacWtmZk1KZ1EyaEE2RUN3SVhRZzlDSDBJTm9RQmhDSEVLQWdqQ0dPSTBSQW1FR01neGtLTWd6Q0ZHQTh4QVdJaXhDU0l5UkJtRU9ZUUZoQlRJQ3docklieHR3ZXZyaVFrT2tTeUJVWmtSVDZEdWFTQWtBSktDaGdwOEVpQlR3b0NVaENTZ29nVXhGQmdJbHhLUWlnSnBTU01rbmlVeEtja0FTVUpLVWxFU1pRUGxQS0JVajVReWdkSytVQXBIeWpsQTZWOG9KUVBsUEtCVWo0dzdnZ21XY0dTb0Mwa2tSUzlvVUhCOGdnWklRM0NGVmU0WXV6ck5zL0hhNTRUd2hOd2VWenVpRmt1SDhFRW1yTkNGTldjUlJBdWw4ZERSczVpWEM1WExQaFh1dlRlRUl5SWk4WWJ4aE5yUmlaQVVNMHNDS3Q4dnFZdXl1WFQyRVVScm9qR0FuMFdQRDROWnhnaUVHbm1SdStOMkU1alFZaGdHSjB1anlZeVlqdE5oVVFZNFZDVEhUcGRCT01UT1d2bzhoQUJEV2RpRE5XMGkvQlVwZERVUlduWVFYaUVPenArVWVIL2x4c2ZFZFBWZ3A1MUhoMi9HRjBXQ0EvbDA3QWpKckw3dDVIUk1rbXdMcWJwWDRSTDA3OUViblM5am5BRmRGMkNDbW1ZSlA1RE5IWUZpRmhUbDh0SE1Sb0xxdjZuaTR5R1g0SUhsS1pUdVZ5NlV3UEQ2Q3BQc0VCMzduQjVkSkZoSWsxdlhCR0thSEpHL0x0Rk5OWGtvM1NuQmpGSlk0RStYb1NyT3RLR2oyTHRvUkducjhINklIa1FKMVFXdERsa3hHSE5sa1ZzNVVpSmVkV0JyYnFqbVRIRTE5RFFVTzdJVTUxVVV0blZJeWNqMTBZSFNVaFRRZEZoYXlVUllSNmZVS3ZCY2c3eXZ3UHk2bUdyOTYwTldyOFJUdWdGUzZLMnlFTmtjS2dURmlJTkdiNHIvaGFFWGtTa1BEeENTb1RCVkwwUFdDUFMxSktObURDSmtxckNYdThVdkNGS3VzbUp1TnlHSHlpcXh3NERKcXpGR0g0RWtiTGVzRThXeVNHTHZNRkNwR0hoUkZRd0hVblF1aEF5YzJPQ1JEVTluRWhadUZST2trN01idUhJSStRVVF3YkJFUkp5WnZnaUhQd0xSbzR5V1pNVEFBQT0ifQ== -->

<div data-pagedtable="false">
  <script data-pagedtable-source type="application/json">
{"columns":[{"label":["p_val"],"name":[1],"type":["dbl"],"align":["right"]},{"label":["avg_logFC"],"name":[2],"type":["dbl"],"align":["right"]},{"label":["pct.1"],"name":[3],"type":["dbl"],"align":["right"]},{"label":["pct.2"],"name":[4],"type":["dbl"],"align":["right"]},{"label":["p_val_adj"],"name":[5],"type":["dbl"],"align":["right"]},{"label":["cluster"],"name":[6],"type":["fctr"],"align":["left"]},{"label":["gene"],"name":[7],"type":["chr"],"align":["left"]}],"data":[{"1":"9.762426e-65","2":"0.7072563","3":"0.733","4":"0.642","5":"4.898786e-61","6":"0","7":"PBANKA-1460400"},{"1":"1.468419e-61","2":"0.8402586","3":"0.675","4":"0.594","5":"7.368526e-58","6":"0","7":"PBANKA-0513600"},{"1":"8.248424e-59","2":"1.6927167","3":"0.615","4":"0.560","5":"4.139059e-55","6":"1","7":"PBANKA-0722600"},{"1":"1.897798e-04","2":"1.3844914","3":"0.226","4":"0.390","5":"9.523152e-01","6":"1","7":"PBANKA-1100441"},{"1":"5.154802e-07","2":"1.1902989","3":"0.424","4":"0.495","5":"2.586680e-03","6":"2","7":"PBANKA-1300096"},{"1":"9.071733e-06","2":"1.1030014","3":"0.213","4":"0.390","5":"4.552196e-02","6":"2","7":"PBANKA-1100441"},{"1":"2.391058e-88","2":"0.8929368","3":"0.829","4":"0.588","5":"1.199833e-84","6":"3","7":"PBANKA-0513600"},{"1":"4.168111e-33","2":"0.8810800","3":"0.558","4":"0.438","5":"2.091558e-29","6":"3","7":"PBANKA-1340000"},{"1":"0.000000e+00","2":"3.0990291","3":"1.000","4":"0.226","5":"0.000000e+00","6":"4","7":"PBANKA-1134900"},{"1":"0.000000e+00","2":"3.0989255","3":"1.000","4":"0.237","5":"0.000000e+00","6":"4","7":"PBANKA-0612400"},{"1":"1.523284e-131","2":"0.9901608","3":"0.990","4":"0.947","5":"7.643840e-128","6":"5","7":"PBANKA-1365500"},{"1":"1.137444e-89","2":"1.0759957","3":"0.820","4":"0.599","5":"5.707695e-86","6":"5","7":"PBANKA-0205000"},{"1":"9.377323e-16","2":"0.8353267","3":"0.255","4":"0.238","5":"4.705541e-12","6":"6","7":"PBANKA-1210800"},{"1":"8.067049e-06","2":"0.9290438","3":"0.435","4":"0.493","5":"4.048045e-02","6":"6","7":"PBANKA-1300096"},{"1":"1.944929e-155","2":"2.2989991","3":"0.792","4":"0.282","5":"9.759652e-152","6":"7","7":"PBANKA-1145400"},{"1":"3.164573e-84","2":"2.0470165","3":"0.717","4":"0.438","5":"1.587983e-80","6":"7","7":"PBANKA-0316841"},{"1":"9.874232e-33","2":"1.2073429","3":"0.642","4":"0.610","5":"4.954889e-29","6":"8","7":"PBANKA-0205000"},{"1":"4.471963e-05","2":"1.1272720","3":"0.485","4":"0.592","5":"2.244031e-01","6":"8","7":"PBANKA-1400400"},{"1":"3.944118e-66","2":"0.8525313","3":"0.875","4":"0.561","5":"1.979158e-62","6":"9","7":"PBANKA-0713300"},{"1":"9.577262e-60","2":"0.9215102","3":"0.673","4":"0.341","5":"4.805870e-56","6":"9","7":"PBANKA-1404800"},{"1":"2.578290e-189","2":"2.0737069","3":"0.997","4":"0.386","5":"1.293786e-185","6":"10","7":"PBANKA-1400600"},{"1":"3.356077e-160","2":"1.7036326","3":"0.955","4":"0.318","5":"1.684079e-156","6":"10","7":"PBANKA-0830200"},{"1":"1.178092e-245","2":"3.2986891","3":"0.990","4":"0.241","5":"5.911666e-242","6":"11","7":"PBANKA-0600600"},{"1":"1.912799e-227","2":"2.9739558","3":"0.987","4":"0.340","5":"9.598423e-224","6":"11","7":"PBANKA-1352100"},{"1":"2.771196e-88","2":"1.0822815","3":"0.924","4":"0.471","5":"1.390586e-84","6":"12","7":"PBANKA-0416500"},{"1":"6.774047e-88","2":"0.9867484","3":"0.982","4":"0.547","5":"3.399217e-84","6":"12","7":"PBANKA-0932200"},{"1":"4.859687e-227","2":"3.0855794","3":"1.000","4":"0.150","5":"2.438591e-223","6":"13","7":"PBANKA-1449000"},{"1":"4.977193e-212","2":"3.0546702","3":"1.000","4":"0.195","5":"2.497555e-208","6":"13","7":"PBANKA-0925400"},{"1":"2.847783e-47","2":"1.2140616","3":"0.529","4":"0.192","5":"1.429018e-43","6":"14","7":"PBANKA-1435200"},{"1":"1.002469e-14","2":"1.5679050","3":"0.286","4":"0.177","5":"5.030392e-11","6":"14","7":"PBANKA-1302700"},{"1":"3.164028e-122","2":"1.3374112","3":"1.000","4":"0.391","5":"1.587709e-118","6":"15","7":"PBANKA-1400600"},{"1":"7.124430e-103","2":"1.3303451","3":"0.924","4":"0.324","5":"3.575039e-99","6":"15","7":"PBANKA-0830200"},{"1":"3.716335e-181","2":"3.6835976","3":"1.000","4":"0.167","5":"1.864857e-177","6":"16","7":"PBANKA-0519400"},{"1":"2.642881e-176","2":"3.4737883","3":"1.000","4":"0.243","5":"1.326198e-172","6":"16","7":"PBANKA-0305000"},{"1":"4.234600e-177","2":"3.9532147","3":"1.000","4":"0.212","5":"2.124922e-173","6":"17","7":"PBANKA-1443300"},{"1":"1.102283e-160","2":"2.9483516","3":"0.995","4":"0.149","5":"5.531257e-157","6":"17","7":"PBANKA-1349000"},{"1":"3.466609e-04","2":"0.8522241","3":"0.239","4":"0.492","5":"1.000000e+00","6":"18","7":"PBANKA-1425100"},{"1":"2.813103e-03","2":"0.7997286","3":"0.202","4":"0.369","5":"1.000000e+00","6":"18","7":"PBANKA-0909200"},{"1":"3.799104e-27","2":"1.0148262","3":"0.626","4":"0.334","5":"1.906390e-23","6":"19","7":"PBANKA-0830200"},{"1":"5.033803e-21","2":"1.0018441","3":"0.667","4":"0.481","5":"2.525962e-17","6":"19","7":"PBANKA-0416500"},{"1":"2.910233e-91","2":"1.7965369","3":"0.911","4":"0.217","5":"1.460355e-87","6":"20","7":"PBANKA-1359900"},{"1":"2.090070e-67","2":"1.9823780","3":"0.863","4":"0.271","5":"1.048797e-63","6":"20","7":"PBANKA-0102400"},{"1":"1.334863e-86","2":"2.4457605","3":"0.904","4":"0.206","5":"6.698341e-83","6":"21","7":"PBANKA-0514900"},{"1":"1.995969e-85","2":"2.2925591","3":"0.886","4":"0.242","5":"1.001577e-81","6":"21","7":"PBANKA-0106300"},{"1":"6.926078e-151","2":"2.9589213","3":"0.993","4":"0.101","5":"3.475506e-147","6":"22","7":"PBANKA-1427700"},{"1":"8.204223e-127","2":"2.5306467","3":"0.974","4":"0.151","5":"4.116879e-123","6":"22","7":"PBANKA-1340400"},{"1":"2.111975e-137","2":"4.1554695","3":"1.000","4":"0.141","5":"1.059789e-133","6":"23","7":"PBANKA-0619700"},{"1":"7.221948e-135","2":"4.4788102","3":"1.000","4":"0.231","5":"3.623974e-131","6":"23","7":"PBANKA-0523700"},{"1":"2.209798e-120","2":"2.5059486","3":"0.993","4":"0.212","5":"1.108877e-116","6":"24","7":"PBANKA-1009600"},{"1":"4.942981e-118","2":"2.3692735","3":"1.000","4":"0.186","5":"2.480388e-114","6":"24","7":"PBANKA-0515000"},{"1":"1.050249e-119","2":"4.3304056","3":"1.000","4":"0.163","5":"5.270152e-116","6":"25","7":"PBANKA-0832800"},{"1":"5.091008e-118","2":"4.3892430","3":"1.000","4":"0.168","5":"2.554668e-114","6":"25","7":"PBANKA-1002600"},{"1":"2.628731e-114","2":"4.9238225","3":"1.000","4":"0.167","5":"1.319097e-110","6":"26","7":"PBANKA-1332700"},{"1":"6.390925e-105","2":"4.2363658","3":"1.000","4":"0.212","5":"3.206966e-101","6":"26","7":"PBANKA-1240600"},{"1":"3.065786e-124","2":"2.7341522","3":"1.000","4":"0.127","5":"1.538411e-120","6":"27","7":"PBANKA-0704700"},{"1":"2.266391e-100","2":"2.3377005","3":"0.990","4":"0.159","5":"1.137275e-96","6":"27","7":"PBANKA-1038800"},{"1":"2.504972e-37","2":"1.9083211","3":"0.960","4":"0.388","5":"1.256995e-33","6":"28","7":"PBANKA-0821900"},{"1":"5.006174e-32","2":"2.2679896","3":"0.947","4":"0.369","5":"2.512098e-28","6":"28","7":"PBANKA-1218100"},{"1":"3.649281e-51","2":"1.7381514","3":"0.985","4":"0.229","5":"1.831209e-47","6":"29","7":"PBANKA-0522400"},{"1":"5.089260e-51","2":"1.9246095","3":"1.000","4":"0.266","5":"2.553790e-47","6":"29","7":"PBANKA-1224900"},{"1":"8.644595e-49","2":"2.3978834","3":"1.000","4":"0.173","5":"4.337858e-45","6":"30","7":"PBANKA-1332700"},{"1":"1.043878e-33","2":"2.2141084","3":"1.000","4":"0.556","5":"5.238182e-30","6":"30","7":"PBANKA-1101100"}],"options":{"columns":{"min":{},"max":[10],"total":[7]},"rows":{"min":[10],"max":[10],"total":[62]},"pages":{}}}
  </script>
</div>

<!-- rnb-frame-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



#### resolution = 4

View

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyMgUGxvdFxuRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDUsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9IFwiRElNX1VNQVBcIiwgZ3JvdXAuYnkgPSBcImludGVncmF0ZWRfc25uX3Jlcy40XCIpICsgY29vcmRfZml4ZWQoKSBcbmBgYCJ9 -->

```r
## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "integrated_snn_res.4") + coord_fixed() 

Make individual plots highlighting where cells in each cluster fall

[1] 46

plot

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]] + list_UMAPs_by_cluster[[27]] + list_UMAPs_by_cluster[[28]] + list_UMAPs_by_cluster[[29]] + list_UMAPs_by_cluster[[30]] + list_UMAPs_by_cluster[[31]] + list_UMAPs_by_cluster[[32]] + list_UMAPs_by_cluster[[33]] + list_UMAPs_by_cluster[[34]] + list_UMAPs_by_cluster[[35]] + list_UMAPs_by_cluster[[36]] + list_UMAPs_by_cluster[[37]] + list_UMAPs_by_cluster[[38]] + list_UMAPs_by_cluster[[39]] + list_UMAPs_by_cluster[[40]] + list_UMAPs_by_cluster[[41]] + list_UMAPs_by_cluster[[42]] + list_UMAPs_by_cluster[[43]] + list_UMAPs_by_cluster[[44]] + list_UMAPs_by_cluster[[45]] + list_UMAPs_by_cluster[[46]]

UMAP clustering

## run a new UMAP with 
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:10, n.components = 10)
00:34:30 UMAP embedding parameters a = 0.9922 b = 1.112
00:34:30 Read 8908 rows and found 10 numeric columns
00:34:30 Using Annoy for neighbor search, n_neighbors = 30
00:34:30 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
00:34:34 Writing NN index file to temp file /var/folders/7t/kvh8b3952x9_4b3r74r1kstc000glh/T//RtmpkxWyey/filed4b4678fa55
00:34:34 Searching Annoy index using 1 thread, search_k = 3000
00:34:37 Annoy recall = 100%
00:36:00 Commencing smooth kNN distance calibration using 1 thread
00:36:05 Initializing from normalized Laplacian + noise
00:36:06 Commencing optimization for 500 epochs, with 366720 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
00:36:40 Optimization finished
## generate new clusters at low resolution
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:10, reduction = "umap")
Computing nearest neighbor graph
Computing SNN
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 0.5, random.seed = 42, algorithm = 2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 8908
Number of edges: 214651

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9475
Number of communities: 26
Elapsed time: 1 seconds
[1] 26

plot

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]]

Pick final resolution

We will look in more detail at cells as they enter the sexual trajecotry later. The PCA clustering will be more appropriate in this high-resolution view. In order to subset these cells, we will use the UMAP clustering.

clusters metrics

We will get some high level insight into these clusters now

6. Define Cluster Identities

We have defined clusters, now we will identify what the clusters correspond to. We can use a number of external datasets to do this:

known marker genes

bulk RNA-seq data correlation

Marker gene expression

expression of 820 markers

## make plots 
plots <- FeaturePlot(tenx.mutant.integrated, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE, dims = c(2,1), reduction = "DIM_UMAP")
    

# Get just the co-expression plot, built-in legend is meaningless for this plot
#plots[[3]] + NoLegend()  

# Get just the key
#plots[[4]] 

# Stitch the co-expression and key plots together
plots[[3]] + NoLegend() + plots[[4]]/plot_spacer() + plot_layout(widths = c(2,1))

Known Marker Genes Plots

marker genes plots

Mutant cells could have aberant expression so we will use only wild-type cells:

make a metadata column where the 10X data is classified as a WT genotype

## get cells that are filtered out
cells_10x <- which(tenx.mutant.integrated@meta.data$experiment == "tenx_5k")

## make extra column in plotting df
tenx.mutant.integrated@meta.data$genotype_combined <- tenx.mutant.integrated@meta.data$genotype
tenx.mutant.integrated@meta.data$genotype_combined[cells_10x] <- "WT"

## inspect
table(tenx.mutant.integrated@meta.data$genotype_combined)

Mutant     WT 
  2028   6880 
wild_type_cells <- rownames(tenx.mutant.integrated@meta.data[tenx.mutant.integrated@meta.data$genotype_combined == "WT", ])
tenx.mutant.integrated.wt <- subset(tenx.mutant.integrated, cells = wild_type_cells)
#FeaturePlot(tenx.mutant.integrated.wt, features = "PBANKA-1101300", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP", pt.size = 1, order = TRUE)

## Run the standard workflow for visualization and clustering
#tenx.mutant.integrated.wt <- ScaleData(tenx.mutant.integrated.wt, verbose = FALSE)
#tenx.mutant.integrated.wt <- RunPCA(tenx.mutant.integrated.wt, npcs = 30, verbose = FALSE)

## inspect PCs
#ElbowPlot(tenx.mutant.integrated.wt, ndims = 30, reduction = "pca")

## Run optimised UMAP
#tenx.mutant.integrated.wt <- RunUMAP(tenx.mutant.integrated.wt, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)

## plot
#dp1 <- DimPlot(tenx.mutant.integrated.wt, label = TRUE, repel = FALSE, pt.size = 0.05, dims = c(2,1), group.by = "experiment") + 
  ## fix the axis
  #coord_fixed() + 
  ## reverse the scale
  #scale_y_reverse()

## view
#dp1
plot_density(tenx.mutant.integrated.wt, markers_list, joint = FALSE, dims = c(2,1), pal = "plasma")

Then define each cluster as Male, Female or Asexual:

## copy clusters to new column
tenx.mutant.integrated@meta.data$cluster_colours_figure <- NA

## define which clusters will be which identity

male_clusters <- c("22", "18", "9", "16")

female_clusters <- c("19","24","20","3")

asex_clusters <- c("8","1","0","4","2","6","7","5","12","14","15","10","23","13","17","21","25")

bipotential_clusters <- c("11")

## check length of the unique entries in the manualy created list above and the number of clusters in total
paste("Is the total number of clusters in the list the same as the number of clusters in the slot?", identical(length(unique(c(male_clusters, female_clusters, asex_clusters, bipotential_clusters))), length(levels(tenx.mutant.integrated@meta.data$seurat_clusters))))
[1] "Is the total number of clusters in the list the same as the number of clusters in the slot? TRUE"
## change the column IDs
tenx.mutant.integrated@meta.data$cluster_colours_figure[which(tenx.mutant.integrated@meta.data$seurat_clusters %in% male_clusters)] <- "Male"
tenx.mutant.integrated@meta.data$cluster_colours_figure[which(tenx.mutant.integrated@meta.data$seurat_clusters %in% female_clusters)] <- "Female"
tenx.mutant.integrated@meta.data$cluster_colours_figure[which(tenx.mutant.integrated@meta.data$seurat_clusters %in% asex_clusters)] <- "Asexual"
tenx.mutant.integrated@meta.data$cluster_colours_figure[which(tenx.mutant.integrated@meta.data$seurat_clusters %in% bipotential_clusters)] <- "Bipotential"

table(tenx.mutant.integrated@meta.data$cluster_colours_figure)

    Asexual Bipotential      Female        Male 
       6934         233         954         787 

7. Plot Figures

useful tools for all plots

## define male and female symbol
female_symbol <- intToUtf8(9792)
male_symbol <- intToUtf8(9794)

Fig. 3.A. (All Cells by Male, Female, Male)

## make a custom pal
# 1 = blue - "#0052c5"
# 2 = red - "#a52b1e"
# 3 = green - "#016c00"
# 4 = yellow - "#ffe400"
pal_sex <- c("#0052c5","#ffe400", "#a52b1e", "#016c00")

UMAP_identity <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.5, group.by = "cluster_colours_figure", dims = c(2,1), reduction = "DIM_UMAP") +
  coord_fixed() + 
  scale_colour_manual(values=pal_sex) + 
  theme_void() + 
  theme(legend.position = "none")

## print
UMAP_identity

save

ggsave("../images_to_export/merge_UMAP_identity.png", plot = UMAP_identity, device = "png", path = NULL, scale = 1, width = 20, height = 20, units = "cm", dpi = 300, limitsize = TRUE)

Fig. Sup. UMAP with Clusters

save

ggsave("../images_to_export/merge_UMAP_cluster.png", plot = umap_cluster, device = "png", path = NULL, scale = 1, width = 20, height = 20, units = "cm", dpi = 300, limitsize = TRUE)

Fig. 3.C. By bulk correlation

## make plots
## hoo dataset correlation
UMAP_hoo <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, group.by = "Prediction.Spearman.", dims = c(2,1), reduction = "DIM_UMAP") +
  coord_fixed() + 
  theme_void() +
  labs(title = paste("Hoo Predicted Timepoint")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold")) +
  scale_colour_manual(values = inferno(12))  +
  labs(colour = "hour") +
  theme(legend.position = "bottom", legend.title=element_text(size=10))

## ap2g timecourse in this paper correlation
UMAP_kasia <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, group.by = "Prediction.Spearman._Kasia", dims = c(2,1), reduction = "DIM_UMAP") +
  coord_fixed() + 
  theme_void() +
  labs(title = paste("AP2G Timecourse Predicted Timepoint")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold")) +
  scale_colour_manual(values = inferno(10))  +
  labs(colour = "hour") +
  theme(legend.position = "bottom", legend.title=element_text(size=10))

## combine
umap_bulk <- wrap_plots(UMAP_hoo, UMAP_kasia, ncol = 2)

## print
umap_bulk

```r
ggsave(\../images_to_export/merge_umap_bulk_prediction.png\, plot = umap_bulk, device = \png\, path = NULL, scale = 1, width = 30, height = 10, units = \cm\, dpi = 300, limitsize = TRUE)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


#### Fig. 3.C. By Experiment

The original method of plotting by experiment does not allow much customisation of the plots. I.e. we cannot easily change the titles of each plot

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyMgUGxvdFxuRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuNSwgc3BsaXQuYnkgPSBcImV4cGVyaW1lbnRcIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gXCJESU1fVU1BUFwiKSArIFxuICBjb29yZF9maXhlZCgpICtcbiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPVwiYm90dG9tXCIsIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLFxuICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSxheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSxcbiAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLFxuICAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCkpXG5gYGAifQ== -->

```r
## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.5, split.by = "experiment", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() +
  theme(legend.position="bottom", axis.line=element_blank(),axis.text.x=element_blank(),
          axis.text.y=element_blank(),axis.ticks=element_blank(),
          axis.title.x=element_blank(),
          axis.title.y=element_blank())

But, we can use the following code to do this

## make an extra meta.data column so you can split the object by SS2 mutant, SS2 WT, 10X
## make new column in meta.data
tenx.mutant.integrated@meta.data$sub_genotype <- tenx.mutant.integrated@meta.data$genotype

## replace NA values from 10X data with a value
tenx.mutant.integrated@meta.data$sub_genotype[is.na(tenx.mutant.integrated@meta.data$sub_genotype)] <- "10X_WT"

## check
table(tenx.mutant.integrated@meta.data$sub_genotype)

10X_WT Mutant     WT 
  6191   2028    689 
## split seurat object up
ob.list <- SplitObject(tenx.mutant.integrated, split.by = "sub_genotype")

## make plots for each object
plot.list <- lapply(X = ob.list, FUN = function(x) {
    DimPlot(x, dims = c(2,1), reduction = "DIM_UMAP", label = FALSE, label.size = 5, repel = TRUE, pt.size = 1) + theme(legend.position="bottom")
})

## use this function to extract legend:
## source: https://stackoverflow.com/questions/13649473/add-a-common-legend-for-combined-ggplots
## source: https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
   tmp <- ggplot_gtable(ggplot_build(a.gplot))
   leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
   legend <- tmp$grobs[[leg]]
   return(legend)}

## make plots pretty
p1 <- plot.list$`10X_WT` + theme_void() + guides(colour=guide_legend(nrow=2,byrow=TRUE, override.aes = list(size=4)))
p2 <- plot.list$WT + theme_void()
p3 <- plot.list$Mutant + theme_void()

## get legend
mylegend<-g_legend(p1)

## make a final plot
p4 <- grid.arrange(arrangeGrob(p1 + theme(legend.position="none") + labs(title = paste("10X", "\n", "(wild-type)")) + theme(plot.title = element_text(hjust = 0.5)),
                               p2 + theme(legend.position="none") + labs(title = paste("Smart-seq2", "\n", "(wild-type)")) + theme(plot.title = element_text(hjust = 0.5)),
                               p3 + theme(legend.position="none") + labs(title = paste("Smart-seq2", "\n", "(mutant)")) + theme(plot.title = element_text(hjust = 0.5)), nrow=1), 
                              mylegend, nrow=2,heights=c(10, 1))

Make final plots:

p1 <- plot.list$`10X_WT` + 
  coord_fixed() +
  theme_void() +
  scale_color_manual(values=c(replicate(45, "#999999"))) +
  labs(title = paste("10X (wild-type)")) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

p2 <- plot.list$WT +
  coord_fixed() +
  theme_void() +
  scale_color_manual(values=c(replicate(46, "#999999"))) +
  labs(title = paste("Smart-seq2 (wild-type)")) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

p3 <- plot.list$Mutant +
  coord_fixed() +
  theme_void() +
  scale_color_manual(values=c(replicate(46, "#999999"))) +
  labs(title = paste("Smart-seq2 (mutant)")) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

p1 + p2 + p3

## make composite plot
UMAP_composite <- wrap_plots(marker_gene_plot_FAMB , marker_gene_plot_MSP8 , marker_gene_plot_MSP1 , marker_gene_plot_AP2G , marker_gene_plot_CCP2 , marker_gene_plot_MG1 , p1 , p2 , p3, ncol = 3)

## print
UMAP_composite

save

```r
ggsave(\../images_to_export/merge_umap_technology_and_markers.png\, plot = UMAP_composite, device = \png\, path = NULL, scale = 1, width = 30, height = 30, units = \cm\, dpi = 300, limitsize = TRUE)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyBQQkFOS0EtMTMxOTUwMCAtIENDUDIgLSBmZW1hbGUgLSB1c2VkIGluIDgyMCBsaW5lXG4jIFBCQU5LQS0wNDE2MTAwIC0gTUcxIC0gZHluZW5pbiBoZWF2eSBjaGFpbiAtIG1hbGUgLSB1c2VkIGluIDgyMCBsaW5lXG4jIFBCQU5LQS0xNDM3NTAwIC0gQVAyRyAtIGNvbW1pdG1lbnRcbiMgUEJBTktBLTA4MzEwMDAgLSBNU1AxIC0gbGF0ZSBhc2V4dWFsXG4jIFBCQU5LQS0xMTAyMjAwIC0gTVNQOCAtIGVhcmx5IGFzZXh1YWwgKGZyb20gQm96ZGVjaCBwYXBlcilcbiMgUEJBTktBLTA3MTE5MDAgLSBIU1A3MCAtIHByb21vdGVyIHVzZWQgZm9yIEdGUCBhbmQgUkZQIGV4cHJlc3Npb24gaW4gdGhlIG11dGFudHNcbiMgUEJBTktBLTE0MDA0MDAgLSBGQU1CIC0gcmluZyBtYXJrZXIgLSBkaXNjb3ZlcmVkIGJ5IGxvb2tpbmcgZm9yIG1hcmtlciBnZW5lcyBpbiBkYXRhXG4jIFBCQU5LQS0wNzIyNjAwIC0gRmFtLWIyIC0gcmluZyBtYXJrZXIgLSBodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM1MTEzMDMxLyBcblxuIyAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PVwiQXJpYWxcIiwgc2l6ZSA9IDIwLCBmYWNlID0gXCJib2xkXCIpKSArIFxuXG5tYXJrZXJzX2xpc3QgPC0gYyhcIlBCQU5LQS0xMzE5NTAwXCIsIFwiUEJBTktBLTA0MTYxMDBcIiwgXCJQQkFOS0EtMTQzNzUwMFwiLCBcIlBCQU5LQS0wODMxMDAwXCIsIFwiUEJBTktBLTExMDIyMDBcIiwgXCJQQkFOS0EtMDcxMTkwMFwiLCBcIlBCQU5LQS0xNDAwNDAwXCIsIFwiUEJBTktBLTA3MjI2MDBcIilcblxubGlzdF9vZl9kZW5zaXR5X3Bsb3RzIDwtIHBsb3RfZGVuc2l0eSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnd0LCBtYXJrZXJzX2xpc3QsIGpvaW50ID0gRkFMU0UsIGNvbWJpbmUgPSBGQUxTRSwgZGltcyA9IGMoMiwxKSwgcGFsID0gXCJwbGFzbWFcIiwgbWV0aG9kID0gXCJrc1wiKVxuXG4jIyBtYWtlIGNvbXBvc2l0ZSBwbG90XG5VTUFQX2NvbXBvc2l0ZSA8LSB3cmFwX3Bsb3RzKGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbOF1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcIkZhbS1iMiAoUmluZylcIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoXCIjRENEQ0RDXCIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gXCJcIikpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzVdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoXCJNU1A4IChBc2V4dWFsKVwiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YyhcIiNEQ0RDRENcIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSBcIlwiKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbNF1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcIk1TUDEgKFNjaGl6b250KVwiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YyhcIiNEQ0RDRENcIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSBcIlwiKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbM11dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcIkFQMkcgKENvbW1pdG1lbnQpXCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKFwiI0RDRENEQ1wiLCBwbGFzbWEoMzApKSApKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9IFwiXCIpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1sxXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgXG4gIGxhYnModGl0bGUgPSBwYXN0ZShcIkNDUDIgKEZlbWFsZSlcIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoXCIjRENEQ0RDXCIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gXCJcIikpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzJdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoXCJNRzEgKE1hbGUpXCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKFwiI0RDRENEQ1wiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9IFwiXCIpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDEgLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDIgLCBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDMsIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMylcbmBgYCJ9 -->

```r
# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-0416100 - MG1 - dynenin heavy chain - male - used in 820 line
# PBANKA-1437500 - AP2G - commitment
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
# PBANKA-0711900 - HSP70 - promoter used for GFP and RFP expression in the mutants
# PBANKA-1400400 - FAMB - ring marker - discovered by looking for marker genes in data
# PBANKA-0722600 - Fam-b2 - ring marker - https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5113031/ 

#  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold")) + 

markers_list <- c("PBANKA-1319500", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200", "PBANKA-0711900", "PBANKA-1400400", "PBANKA-0722600")

list_of_density_plots <- plot_density(tenx.mutant.integrated.wt, markers_list, joint = FALSE, combine = FALSE, dims = c(2,1), pal = "plasma", method = "ks")

## make composite plot
UMAP_composite <- wrap_plots(list_of_density_plots[[8]] + coord_fixed() + theme_void() + labs(title = paste("Fam-b2 (Ring)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots[[5]] + coord_fixed() + theme_void() + labs(title = paste("MSP8 (Asexual)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots[[4]] + coord_fixed() + theme_void() + labs(title = paste("MSP1 (Schizont)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots[[3]] + coord_fixed() + theme_void() + labs(title = paste("AP2G (Commitment)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30)) )+ guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots[[1]] + coord_fixed() + theme_void() + 
  labs(title = paste("CCP2 (Female)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots[[2]] + coord_fixed() + theme_void() + labs(title = paste("MG1 (Male)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             p1 , 
                             p2 , 
                             p3, 
                             ncol = 3)
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
UMAP_composite

Specific gene expression of mutants

save

```r
ggsave(\../images_to_export/merge_umap_mutant_gene_expression.png\, plot = mutant_expression_composite, device = \png\, path = NULL, scale = 1, width = 30, height = 30, units = \cm\, dpi = 300, limitsize = TRUE)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Density plot version


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyBQQkFOS0EtMDgyODAwMCAgICAgICAgIEdDU0tPLTMgIEdEMVxuXG4jIFBCQU5LQS0xMzAyNzAwICAgICAgIEdDU0tPLW9vbSAgTUQxIFxuIyBQQkFOS0EtMTQ0NzkwMCAgICAgICAgR0NTS08tMjkgIE1EMlxuIyBQQkFOS0EtMDEwMjQwMCAgICAgICAgIEdDU0tPLTIgIE1EMyBcbiMgUEJBTktBLTA3MTY1MDAgICAgICAgIEdDU0tPLTE5ICBNRDQgXG4jIFBCQU5LQS0wNDEzNDAwICAgIEdDU0tPLTEwXzgyMCAgTUQ1XG5cbiMgUEJBTktBLTE0NTQ4MDAgICAgICAgIEdDU0tPLTIxICBGRDFcbiMgUEJBTktBLTA5MDIzMDAgICAgICAgIEdDU0tPLTEzICBGRDJcbiMgUEJBTktBLTE0MTgxMDAgICAgICAgIEdDU0tPLTE3ICBGRDMgICBcbiMgUEJBTktBLTE0MzUyMDAgICAgICAgIEdDU0tPLTIwICBGRDQgXG5cbm1hcmtlcnNfbGlzdCA8LSBjKFwiUEJBTktBLTA4MjgwMDBcIiwgXCJQQkFOS0EtMTMwMjcwMFwiLCBcIlBCQU5LQS0xNDQ3OTAwXCIsIFwiUEJBTktBLTAxMDI0MDBcIiwgXCJQQkFOS0EtMDcxNjUwMFwiLCBcIlBCQU5LQS0wNDEzNDAwXCIsIFwiUEJBTktBLTE0NTQ4MDBcIiwgXCJQQkFOS0EtMDkwMjMwMFwiLCBcIlBCQU5LQS0xNDE4MTAwXCIsIFwiUEJBTktBLTE0MzUyMDBcIilcblxubGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lcyA8LSBwbG90X2RlbnNpdHkodGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dCwgbWFya2Vyc19saXN0LCBqb2ludCA9IEZBTFNFLCBjb21iaW5lID0gRkFMU0UsIGRpbXMgPSBjKDIsMSksIHBhbCA9IFwicGxhc21hXCIsIG1ldGhvZCA9IFwia3NcIilcblxuIyMgbWFrZSBjb21wb3NpdGUgcGxvdFxuVU1BUF9jb21wb3NpdGVfbXV0YW50X2dlbmVzIDwtIHdyYXBfcGxvdHMobGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbMV1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcImdkMVwiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YyhcIiNEQ0RDRENcIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSBcIlwiKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzJdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoXCJtZDFcIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoXCIjRENEQ0RDXCIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gXCJcIikpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNfbXV0YW50X2dlbmVzW1szXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgbGFicyh0aXRsZSA9IHBhc3RlKFwibWQyXCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKFwiI0RDRENEQ1wiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9IFwiXCIpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbNF1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcIm1kM1wiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YyhcIiNEQ0RDRENcIiwgcGxhc21hKDMwKSkgKSsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSBcIlwiKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzVdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBcbiAgbGFicyh0aXRsZSA9IHBhc3RlKFwibWQ0XCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKFwiI0RDRENEQ1wiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9IFwiXCIpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbNl1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcIm1kNVwiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YyhcIiNEQ0RDRENcIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSBcIlwiKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzddXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoXCJmZDFcIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoXCIjRENEQ0RDXCIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gXCJcIikpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNfbXV0YW50X2dlbmVzW1s4XV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgbGFicyh0aXRsZSA9IHBhc3RlKFwiZmQyXCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKFwiI0RDRENEQ1wiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9IFwiXCIpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbOV1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIGxhYnModGl0bGUgPSBwYXN0ZShcImZkM1wiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YyhcIiNEQ0RDRENcIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSBcIlwiKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzEwXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgbGFicyh0aXRsZSA9IHBhc3RlKFwiZmQ0XCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKFwiI0RDRENEQ1wiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9IFwiXCIpKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDQpXG5gYGAifQ== -->

```r
# PBANKA-0828000         GCSKO-3  GD1

# PBANKA-1302700       GCSKO-oom  MD1 
# PBANKA-1447900        GCSKO-29  MD2
# PBANKA-0102400         GCSKO-2  MD3 
# PBANKA-0716500        GCSKO-19  MD4 
# PBANKA-0413400    GCSKO-10_820  MD5

# PBANKA-1454800        GCSKO-21  FD1
# PBANKA-0902300        GCSKO-13  FD2
# PBANKA-1418100        GCSKO-17  FD3   
# PBANKA-1435200        GCSKO-20  FD4 

markers_list <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-0413400", "PBANKA-1454800", "PBANKA-0902300", "PBANKA-1418100", "PBANKA-1435200")

list_of_density_plots_mutant_genes <- plot_density(tenx.mutant.integrated.wt, markers_list, joint = FALSE, combine = FALSE, dims = c(2,1), pal = "plasma", method = "ks")

## make composite plot
UMAP_composite_mutant_genes <- wrap_plots(list_of_density_plots_mutant_genes[[1]] + coord_fixed() + theme_void() + labs(title = paste("gd1")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[2]] + coord_fixed() + theme_void() + labs(title = paste("md1")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[3]] + coord_fixed() + theme_void() + labs(title = paste("md2")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[4]] + coord_fixed() + theme_void() + labs(title = paste("md3")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30)) )+ guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[5]] + coord_fixed() + theme_void() + 
  labs(title = paste("md4")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[6]] + coord_fixed() + theme_void() + labs(title = paste("md5")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[7]] + coord_fixed() + theme_void() + labs(title = paste("fd1")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[8]] + coord_fixed() + theme_void() + labs(title = paste("fd2")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[9]] + coord_fixed() + theme_void() + labs(title = paste("fd3")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             list_of_density_plots_mutant_genes[[10]] + coord_fixed() + theme_void() + labs(title = paste("fd4")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, title = "")),
                             ncol = 4)
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
UMAP_composite_mutant_genes

save

ggsave("../images_to_export/merge_umap_mutant_gene_expression.png", plot = UMAP_composite_mutant_genes, device = "png", path = NULL, scale = 1, width = 30, height = 30, units = "cm", dpi = 300, limitsize = TRUE)

Fig. Sup. Look at specific mutants

All the mutant genotypes profiled were:

## make a list of possible genotypes
unique(tenx.mutant.integrated@meta.data$identity_updated)
 [1] NA             "GCSKO-oom"    "WT"           "GCSKO-29"     "GCSKO-21"     "GCSKO-17"     "GCSKO-2"     
 [8] "GCSKO-19"     "GCSKO-20"     "GCSKO-13"     "GCSKO-10_820" "GCSKO-3"     
unique(tenx.mutant.integrated@meta.data$identity_name_updated)
 [1] NA          "md1"       "wild-type" "md2"       "fd1"       "fd3"       "md3"       "md4"       "fd4"      
[10] "fd2"       "md5"       "gd1"      
# PBANKA-0828000         GCSKO-3  GD1

# PBANKA-1302700       GCSKO-oom  MD1 
# PBANKA-1447900        GCSKO-29  MD2
# PBANKA-0102400         GCSKO-2  MD3 
# PBANKA-0716500        GCSKO-19  MD4 
# PBANKA-0413400    GCSKO-10_820  MD5

# PBANKA-1454800        GCSKO-21  FD1
# PBANKA-0902300        GCSKO-13  FD2
# PBANKA-1418100        GCSKO-17  FD3   
# PBANKA-1435200        GCSKO-20  FD4 

## ~ TODO ~ MAKE INTO A FOR LOOP

## make lists for each genotype
cells_17 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-17"), ])
cells_2 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-2"), ])
cells_19 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-19"), ])
cells_20 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-20"), ])
cells_13 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-13"), ])
cells_10 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-10_820"), ])
cells_3 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-3"), ])
cells_oom <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-oom"), ])
cells_29 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-29"), ])
cells_21 <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$identity_updated == "GCSKO-21"), ])

## make plots

pm2 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_17, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("fd3","\n", "(PBANKA_1418100)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm3 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_2, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("md3","\n", "(PBANKA_0102400)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm4 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_19, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) +
  theme_void() + 
  labs(title = paste("md4","\n", "(PBANKA_0716500)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm5 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_20, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("fd4","\n", "(PBANKA_1435200)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm6 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_13, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("fd2","\n", "PBANKA_0902300")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm7 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_10, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("md5","\n", "(PBANKA_0413400)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm8 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_3, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("gd1","\n", "(PBANKA_0828000)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm9 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_oom, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("md1","\n", "(PBANKA_1302700)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm10 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_29, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("md2","\n", "(PBANKA_1447900)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pm11 <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = cells_21, group.by = "exclude_for_sex_ratio", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("fd1","\n", "(PBANKA_1454800)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 15, face = "bold"), legend.position = "none")  +
  ## add sex symbols
  annotate("text", x = 3.8, y = 1.5, label = male_symbol, size=7, color="gray") + 
  annotate("text", x = 2, y = 2.8, label = female_symbol, size=7, color="gray")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
## plot composite plot
## not used as outside plots have odd sizes
#pm1 + pm2 + pm4 + pm5 + pm11 + pm7 + pm6 + pm8 + pm9 + pm10 + pm3

## plot composite plot
mutant_cell_locations <- plot_grid(pm2 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm4 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm5 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm11 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm7 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm6 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm8 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm9 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm10 + theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), pm3+ theme(plot.margin = unit(c(0, 0, 0, 0), "cm")), nrow = 3)
font family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font databasefont family 'Arial' not found in PostScript font database
## print
mutant_cell_locations

save

```r
ggsave(\/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/merge_umap_mutant_cell_locations.png\, plot = mutant_cell_locations, device = \png\, path = NULL, scale = 1, width = 30, height = 30, units = \cm\, dpi = 300, limitsize = TRUE)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### Figure. Sup. Dot Plot Figures

#### Expression of Marker Genes by Cluster

We will use the following marker genes:

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuIyBQQkFOS0EtMTMxOTUwMCAtIENDUDIgLSBmZW1hbGUgLSB1c2VkIGluIDgyMCBsaW5lXG4jIFBCQU5LQS0wNDE2MTAwIC0gTUcxIC0gZHluZW5pbiBoZWF2eSBjaGFpbiAtIG1hbGUgLSB1c2VkIGluIDgyMCBsaW5lXG4jIFBCQU5LQS0wODMxMDAwIC0gTVNQMSAtIGxhdGUgYXNleHVhbFxuIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpXG4jIFBCQU5LQS0xNDM3NTAwIC0gQVAyRyAtIGNvbW1pdG1lbnRcbmBgYFxuYGBgIn0= -->

```r
```r
# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-0416100 - MG1 - dynenin heavy chain - male - used in 820 line
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
# PBANKA-1437500 - AP2G - commitment

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


plot expression of these marker genes in each cluster

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyMgY29weSB0aGUgY2x1c3RlcnMgc28geW91IGRvbid0IHBlcm1hbmVudGx5IGVkaXQgdGhlIG1hc3RlclxudGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQud3RAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVyc1xuXG4jIyByZW9yZGVyIHRoZSBsZXZlbHMgc28geW91IGNhbiBwbG90IHRoZSBjbHV0ZXJzIGFzIHlvdSB3aXNoXG5teV9sZXZlbHMgPC0gYyhhc2V4X2NsdXN0ZXJzLCBiaXBvdGVudGlhbF9jbHVzdGVycywgbWFsZV9jbHVzdGVycywgZmVtYWxlX2NsdXN0ZXJzKVxuXG4jIyByZW9yZGVyIHRoZSBsZXZlbHNcbnRlbngubXV0YW50LmludGVncmF0ZWQud3RAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVyc19wbG90dGluZyA8LSBmYWN0b3IoeCA9IHRlbngubXV0YW50LmludGVncmF0ZWQud3RAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVyc19wbG90dGluZywgbGV2ZWxzID0gbXlfbGV2ZWxzKVxuXG4jIyBwbG90XG5kb3RfcGxvdF9tYXJrZXJzIDwtIERvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dCwgZmVhdHVyZXMgPSBjKFwiUEJBTktBLTEzMTk1MDBcIiwgXCJQQkFOS0EtMDQxNjEwMFwiLCBcIlBCQU5LQS0xNDM3NTAwXCIsIFwiUEJBTktBLTA4MzEwMDBcIiwgXCJQQkFOS0EtMTEwMjIwMFwiKSwgZ3JvdXAuYnkgPSBcInNldXJhdF9jbHVzdGVyc19wbG90dGluZ1wiKSArXG4gIHRoZW1lX2NsYXNzaWMoKSArXG4gICMgY2hhbmdlIGFwcGVhcmFuY2UgYW5kIHJlbW92ZSBheGlzIGVsZW1lbnRzLCBhbmQgbWFrZSByb29tIGZvciBhcnJvd3NcbiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNiwgYW5nbGUgPSA0NSwgaGp1c3Q9MSx2anVzdD0xLCBmYW1pbHkgPSBcIkFyaWFsXCIpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2LCBmYW1pbHk9XCJBcmlhbFwiKSwgbGVnZW5kLnBvc2l0aW9uID0gXCJib3R0b21cIiwgbGVnZW5kLmRpcmVjdGlvbiA9IFwiaG9yaXpvbnRhbFwiLCBsZWdlbmQuYm94ID0gXCJ2ZXJ0aWNhbFwiLCBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwzKSwgXCJsaW5lc1wiKSkgK1xuICAjY2hhbmdlIHRoZSBjb2xvdXJzXG4gIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9IFwiaW5mZXJub1wiLCBndWlkZSA9IFwiY29sb3VyYmFyXCIsIG5hLnZhbHVlPVwid2hpdGVcIiwgYmVnaW4gPSAwLCBlbmQgPSAxLCBkaXJlY3Rpb24gPSAxKSArXG4gICMjIGNoYW5nZSB4IGF4aXMgbGFiZWxcbiAgbGFicyh4ID0gXCJNYXJrZXIgR2VuZXNcIiwgeSA9IFwiQ2x1c3RlclwiLCB0aXRsZSA9IFwiRXhwcmVzc2lvbiBvZiBNYXJrZXIgR2VuZXMgYnkgQ2x1c3RlclwiKSArXG4gICMjIGFkZCBhcnJvd3NcbiAgI2Fubm90YXRlKFwic2VnbWVudFwiLCB4ID0gNS41LCB4ZW5kID0gNS41LCB5ID0gMjEuNSwgeWVuZCA9IDI1LCBjb2xvdXIgPSBcImdyZWVuXCIsIHNpemU9MSwgYWxwaGE9MSwgYXJyb3c9YXJyb3cobGVuZ3RoPXVuaXQoMC4zMCxcImNtXCIpLCB0eXBlID0gXCJjbG9zZWRcIikpICtcbiAgI2Fubm90YXRlKFwic2VnbWVudFwiLCB4ID0gNS41LCB4ZW5kID0gNS41LCB5ID0gMTYuNSwgeWVuZCA9IDIxLjUsIGNvbG91ciA9IFwicmVkXCIsIHNpemU9MSwgYWxwaGE9MSwgYXJyb3c9YXJyb3cobGVuZ3RoPXVuaXQoMC4zMCxcImNtXCIpLCB0eXBlID0gXCJjbG9zZWRcIikpICtcbiAgI2Fubm90YXRlKFwic2VnbWVudFwiLCB4ID0gNS41LCB4ZW5kID0gNS41LCB5ID0gMCwgeWVuZCA9IDE1LjUsIGNvbG91ciA9IFwiZ3JleVwiLCBzaXplPTEsIGFscGhhPTEsIGFycm93PWFycm93KGxlbmd0aD11bml0KDAuMzAsXCJjbVwiKSwgdHlwZSA9IFwiY2xvc2VkXCIpKSArXG4gICMjIGFubm90YXRlIGFzZXhcbiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IChsZW5ndGgoYXNleF9jbHVzdGVycykrMC41KSkpICtcbiAgIyMgYW5ub3RhdGUgYmlwb3RlbnRpYWxcbiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IChsZW5ndGgoYyhhc2V4X2NsdXN0ZXJzLCBiaXBvdGVudGlhbF9jbHVzdGVycykpKzAuNSkpKSArXG4gICMjIGFubm90YXRlIHNleGVzXG4gIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAobGVuZ3RoKGMoYXNleF9jbHVzdGVycywgYmlwb3RlbnRpYWxfY2x1c3RlcnMsIG1hbGVfY2x1c3RlcnMpKSswLjUpKSkgK1xuICAjIyBjaGFuZ2UgbGFiZWwgb24gYm90dG9tIG9mIHBsb3Qgc28gd2UgY2FuIGluZGljYXRlIG1hcmtlcnNcbiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSByZXYoYyhwYXN0ZShcIlBCQU5LQS0xMTAyMjAwXCIsXCJcXG5cIiwgXCIoTVNQODsgZWFybHkgYXNleHVhbClcIiksIHBhc3RlKFwiUEJBTktBLTA4MzEwMDBcIixcIlxcblwiLCBcIihNU1AxOyBsYXRlIGFzZXh1YWwpXCIpLCBwYXN0ZShcIlBCQU5LQS0xNDM3NTAwXCIsIFwiXFxuXCIsIFwiKEFQMkc7IHNleHVhbCBjb21taXRtZW50KVwiKSwgcGFzdGUoXCJQQkFOS0EtMDQxNjEwMFwiLCBcIlxcblwiLCBcIihNRzE7IG1hbGUpXCIpLCBwYXN0ZShcIlBCQU5LQS0xMzE5NTAwXCIsIFwiXFxuXCIsIFwiKENDUDI7IGZlbWFsZSlcIikpKSlcbmBgYCJ9 -->

```r
## copy the clusters so you don't permanently edit the master
tenx.mutant.integrated.wt@meta.data$seurat_clusters_plotting <- tenx.mutant.integrated.wt@meta.data$seurat_clusters

## reorder the levels so you can plot the cluters as you wish
my_levels <- c(asex_clusters, bipotential_clusters, male_clusters, female_clusters)

## reorder the levels
tenx.mutant.integrated.wt@meta.data$seurat_clusters_plotting <- factor(x = tenx.mutant.integrated.wt@meta.data$seurat_clusters_plotting, levels = my_levels)

## plot
dot_plot_markers <- DotPlot(tenx.mutant.integrated.wt, features = c("PBANKA-1319500", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), group.by = "seurat_clusters_plotting") +
  theme_classic() +
  # change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=16, angle = 45, hjust=1,vjust=1, family = "Arial"), text=element_text(size=16, family="Arial"), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", plot.title = element_blank(), plot.margin = unit(c(1,3,1,3), "lines")) +
  #change the colours
  scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes", y = "Cluster", title = "Expression of Marker Genes by Cluster") +
  ## add arrows
  #annotate("segment", x = 5.5, xend = 5.5, y = 21.5, yend = 25, colour = "green", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  #annotate("segment", x = 5.5, xend = 5.5, y = 16.5, yend = 21.5, colour = "red", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  #annotate("segment", x = 5.5, xend = 5.5, y = 0, yend = 15.5, colour = "grey", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  ## annotate asex
  geom_hline(aes(yintercept = (length(asex_clusters)+0.5))) +
  ## annotate bipotential
  geom_hline(aes(yintercept = (length(c(asex_clusters, bipotential_clusters))+0.5))) +
  ## annotate sexes
  geom_hline(aes(yintercept = (length(c(asex_clusters, bipotential_clusters, male_clusters))+0.5))) +
  ## change label on bottom of plot so we can indicate markers
  scale_x_discrete(labels = rev(c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)"))))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
## view
print(dot_plot_markers)

Expression of the mutant genes by cluster

gene identities for the mutants profiled

# PBANKA-0828000         GCSKO-3  GD1

# PBANKA-1302700       GCSKO-oom  MD1 
# PBANKA-1447900        GCSKO-29  MD2
# PBANKA-0102400         GCSKO-2  MD3 
# PBANKA-0716500        GCSKO-19  MD4 
# PBANKA-0413400    GCSKO-10_820  MD5

# PBANKA-1454800        GCSKO-21  FD1
# PBANKA-0902300        GCSKO-13  FD2
# PBANKA-1418100        GCSKO-17  FD3   
# PBANKA-1435200        GCSKO-20  FD4 

plot expression of these mutant genes by cluster

## plot
dot_plot_mutant_genes <- DotPlot(tenx.mutant.integrated.wt, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500","PBANKA-1454800", "PBANKA-1418100", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1435200"), group.by = "seurat_clusters_plotting") +
  theme_classic() +
  ## change appearance and remove axis elements, and make room for arrows, and also change posoition of legends relative to one another
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", plot.margin = unit(c(1,3,1,3), "lines"), text=element_text(size=16, family="Arial")) +
  ##add these to above to remove y = plot.title = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.title.y = element_blank()
  ## change the colours
  scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Mutant Genes",  title = "Expression of mutant genes by cluster", y = "Cluster") +
  ## annotate asex
  geom_hline(aes(yintercept = (length(asex_clusters)+0.5))) +
  ## annotate bipotential
  geom_hline(aes(yintercept = (length(c(asex_clusters, bipotential_clusters))+0.5))) +
  ## annotate sexes
  geom_hline(aes(yintercept = (length(c(asex_clusters, bipotential_clusters, male_clusters))+0.5))) +
  ## change label on bottom of plot so we can indicate markers
  scale_x_discrete(labels = rev(c(paste("PBANKA-1435200", "\n", "fd4"),
                                  paste("PBANKA-0413400","\n", "md5"),
                                  paste("PBANKA-0902300", "\n", "fd2"),
                                  paste("PBANKA-1418100", "\n", "fd3"),
                                  paste("PBANKA_1454800","\n", "fd1"),
                                  paste("PBANKA-0716500", "\n", "md4"),
                                  paste("PBANKA-0102400", "\n", "md3"),
                                  paste("PBANKA-1447900", "\n", "md2"),
                                  paste("PBANKA-1302700", "\n", "md1"),
                                  paste("PBANKA-0828000", "\n", "gd1"))))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
## view
print(dot_plot_mutant_genes)

Representation of Experiment by Cluster

make a metadata column where the 10X data is classified as a WT genotype

## get cells that are filtered out
cells_10x <- which(tenx.mutant.integrated@meta.data$experiment == "tenx_5k")

## make extra column in plotting df
tenx.mutant.integrated@meta.data$genotype_combined <- tenx.mutant.integrated@meta.data$genotype
tenx.mutant.integrated@meta.data$genotype_combined[cells_10x] <- "WT"

## inspect
table(tenx.mutant.integrated@meta.data$genotype_combined)

Mutant     WT 
  2028   6880 

Plot expression of mutant genes by cluster (which is subdivided by genotype)

This is kind of a control because the mutant should express less of the gene of interest at some point due to the inclusion of the mutant cells

## plot
dot_plot_mutant_genes_genotype <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800"), group.by = "seurat_clusters_plotting", split.by = "genotype_combined") +
  ## make appearance smoother
  theme_classic() +
  ## change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", plot.title = element_blank(), plot.margin = unit(c(1,3,1,1), "lines")) +
  ## change the colours
  #scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes") +
  ## annotate males
  geom_hline(aes(yintercept = 56.5)) +
  ## annotate females
  geom_hline(aes(yintercept = 48.5)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 46.5))
  ## change label on bottom of plot so we can indicate markers
  #scale_x_discrete(labels = c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)")))

## view
print(dot_plot_mutant_genes_genotype)

## plot
dot_plot_mutants_experiment <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800"), group.by = "seurat_clusters_plotting", split.by = "sub_genotype", cols = c("red", "blue", "green")) +
  theme_classic() +
  # change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", plot.title = element_blank(), plot.margin = unit(c(1,3,1,1), "lines")) +
  #change the colours
  #scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes") +
  ## annotate males
  geom_hline(aes(yintercept = 77)) +
  ## annotate females
  geom_hline(aes(yintercept = 61)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 59))
  ## change label on bottom of plot so we can indicate markers
  #scale_x_discrete(labels = c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)")))

## view
print(dot_plot_mutants_experiment)

Representation of mutants in clusters

Add a meta.data column so that 10X is listed as WT:

## get cells that are filtered out
mutant_cells <- which(tenx.mutant.integrated$experiment == "mutants")

## make extra column in plotting df
tenx.mutant.integrated@meta.data$identity_combined <- "WT_10X"
tenx.mutant.integrated@meta.data$identity_combined[mutant_cells] <- tenx.mutant.integrated@meta.data$identity_updated[mutant_cells]

prepare data for dotplotting

## make a dataframe that is a copy of the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated@meta.data)

## redefine order of clusters:
df_meta_data$seurat_clusters <- factor(x = df_meta_data$seurat_clusters, levels = my_levels)

## make a new df of CLUSTER and IDENTITY
dot_plot_df <- as.data.frame.matrix(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined))
dot_plot_df$cluster <- rownames(dot_plot_df)

## calculate percentage of cells for each genotype
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined), margin = 2)) * 100)

## make a column for cluster names
dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)

## melt dataframe for plotting
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
Using cluster as id variables
colnames(dot_plot_df_pc_melted)[2] <- "identity"

## melt the raw number too
dot_plot_df_melted <- melt(dot_plot_df, variable.name = "cluster")
Using cluster as id variables
colnames(dot_plot_df_melted)[2] <- "identity"
colnames(dot_plot_df_melted)[3] <- "raw_number"

## merge together
identical(dot_plot_df_melted$cluster, dot_plot_df_pc_melted$cluster)
[1] TRUE
dot_plot_merged <- cbind(dot_plot_df_melted, dot_plot_df_pc_melted)
dot_plot_merged <- dot_plot_merged[,c(1,2,3,6)]

## redefine order of clusters
dot_plot_merged$cluster <- factor(x = dot_plot_merged$cluster, levels = my_levels)

## where values are zero, add NA
## find wells where it's zero
zero_values <- dot_plot_merged$value == 0
dot_plot_merged$value[zero_values] <- NA

## also do for raw number
zero_values <- dot_plot_merged$raw_number == 0
dot_plot_merged$raw_number[zero_values] <- NA

## reorder x axis:
my_levels_genotype <- c("GCSKO-oom", "GCSKO-29", "GCSKO-3", "GCSKO-2", "GCSKO-19", "GCSKO-28", "GCSKO-21", "GCSKO-13", "GCSKO-17", "GCSKO-20", "GCSKO-10_820", "WT", "WT_10X")

dot_plot_merged$identity <- factor(x = dot_plot_df_pc_melted$identity, levels = my_levels_genotype)

plot

dot_plot_identity <- ggplot(dot_plot_merged, aes(y = factor(cluster), x = factor(identity))) +
      ## make into a dot plot
      geom_point(aes(colour=value, size=raw_number)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 0, max(dot_plot_df_pc_melted$value)), na.value="white") +
      #change the colours
      scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white") +
      theme_classic() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank()) +
      ylab("Cluster") +
      xlab("Identity") +
      labs(colour = "% cells of that genotype represented in that cluster", size = "number of cells of that genotype represented in that cluster") +
      theme(axis.text.x=element_text(size=12, angle=45, hjust=1, vjust=1), axis.text.y=element_text(size=12), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", text=element_text(size=16,  family="Arial")) +
  ## annotate asex
  geom_hline(aes(yintercept = (length(asex_clusters)+0.5))) +
  ## annotate bipotential
  geom_hline(aes(yintercept = (length(c(asex_clusters, bipotential_clusters))+0.5))) +
  ## annotate sexes
  geom_hline(aes(yintercept = (length(c(asex_clusters, bipotential_clusters, male_clusters))+0.5)))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
#title = "% genotype population found in each cluster", 

print(dot_plot_identity)

maybe the respresentation differences have batch-effects:

```r
#table(tenx.mutant.integrated@meta.data$sort_date, tenx.mutant.integrated@meta.data$identity_updated)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


#### Compose Final Plot

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuZG90X3Bsb3RfaWRlbnRpdHkgKyBkb3RfcGxvdF9tYXJrZXJzICsgZG90X3Bsb3RfbXV0YW50X2dlbmVzXG5gYGAifQ== -->

```r
dot_plot_identity + dot_plot_markers + dot_plot_mutant_genes

8. Subset sexual cells

Make a subsetted Seurat object of sexual cells.

Include the pre-branch too as well as any weird clusters that may have clustered out.

it’s been a while since we looked at the clusters so let’s check them out again:

Define cells and subset

## define cells
## 2 and 0 are at the beginning of the stalk
sex_clusters <- c(bipotential_clusters, female_clusters, male_clusters, "5", "7")

## subset cells into new object
tenx.mutant.integrated.sex <- subset(tenx.mutant.integrated, idents = sex_clusters)

inspect/check

## inspect object
tenx.mutant.integrated.sex
An object of class Seurat 
10116 features across 3020 samples within 2 assays 
Active assay: integrated (5018 features, 2000 variable features)
 1 other assay present: RNA
 3 dimensional reductions calculated: pca, umap, DIM_UMAP
## look at original UMAP
DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, pt.size = 0.1, split.by = "experiment", dims = c(2,1), reduction = "DIM_UMAP") + coord_fixed()

Remove contaminant asexual cells

we want to remove:

## look at original UMAP
plot_sexual_subsetting <- DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, pt.size = 0.1, dims = c(2,1), reduction = "DIM_UMAP") + coord_fixed() + geom_hline(aes(yintercept = -0.80, alpha = 5)) + geom_vline(aes(xintercept = -0.1, alpha = 5))

plot_sexual_subsetting

Look interactively:

HoverLocator(plot = plot_sexual_subsetting, information = FetchData(object = tenx.mutant.integrated.sex, vars = 'identity_name_updated'))
`arrange_()` is deprecated as of dplyr 0.7.0.
Please use `arrange()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used`error_y.color` does not currently support multiple values.`error_x.color` does not currently support multiple values.`line.color` does not currently support multiple values.The titlefont attribute is deprecated. Use title = list(font = ...) instead.the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used`error_y.color` does not currently support multiple values.`error_x.color` does not currently support multiple values.`line.color` does not currently support multiple values.The titlefont attribute is deprecated. Use title = list(font = ...) instead.
## extract cell embeddings
df_sex_cell_embeddings <- as.data.frame(tenx.mutant.integrated.sex@reductions[["DIM_UMAP"]]@cell.embeddings)

## subset anything lower than -0.8 in UMAP 2 and -0.1 in UMAP 1
remove_cells <- row.names(df_sex_cell_embeddings[which(df_sex_cell_embeddings$DIMUMAP_2 < -0.1 | df_sex_cell_embeddings$DIMUMAP_1 < -0.8), ])

## plot these cells
DimPlot(tenx.mutant.integrated.sex, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = remove_cells, dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cells highlighted will be removed")) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.

DimPlot(tenx.mutant.integrated.sex, label = FALSE, repel = TRUE, pt.size = 1, dims = c(2,1), reduction = "DIM_UMAP", group.by = "identity_combined") + 
  coord_fixed() 

then check what the IDs of these cells are to ensure they aren’t a genuine mutant signature

tenx.mutant.integrated.sex@meta.data[rownames(tenx.mutant.integrated.sex@meta.data) %in% remove_cells, ]$identity_combined
[1] "WT_10X"       "GCSKO-21"     "GCSKO-21"     "GCSKO-19"     "WT"           "GCSKO-10_820"
[7] "GCSKO-10_820" "WT"          

Although there are a number of GCSKO-21 cells, there are still many remaining in the sex cluster above and the cells near the asexual cycle also have a GCSKO-17 cell with them and are therefore not exclusively belonging to that mutant so we will remove these cells.

Final Subset

## make keep cells from the remove_cells
## make the not in function
'%ni%' <- Negate('%in%')
keep_cells <- colnames(tenx.mutant.integrated.sex)[which(colnames(tenx.mutant.integrated.sex) %ni% remove_cells)]

## subset
tenx.mutant.integrated.sex <- subset(tenx.mutant.integrated.sex, cells = keep_cells)

## inspect
tenx.mutant.integrated.sex
An object of class Seurat 
10116 features across 3012 samples within 2 assays 
Active assay: integrated (5018 features, 2000 variable features)
 1 other assay present: RNA
 3 dimensional reductions calculated: pca, umap, DIM_UMAP

copy old clusters over

## copy old clusters
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, tenx.mutant.integrated.sex@meta.data$seurat_clusters, col.name = "post_integration_clusters")

9. Pseudotime on all cells

Pseudotime calculation

## extract data from Seurat
seurat.object.all <- tenx.mutant.integrated
# counts
data <- as(as.matrix(GetAssayData(seurat.object.all, assay = "integrated", slot = "data")), 'sparseMatrix')
# meta data
pd <- data.frame(seurat.object.all@meta.data)

## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
## add gene short name
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object.all <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
monocle.object.all = preprocess_cds(monocle.object.all, num_dim = 100, norm_method = "none")
## plot variance explained plot
plot_pc_variance_explained(monocle.object.all)

## make monocle UMAP
#monocle.object.all = reduce_dimension(monocle.object.all, reduction_method = "UMAP", preprocess_method = "PCA", umap.metric = "euclidean", umap.n_neighbors = 20, umap.min_dist = 0.5, verbose = FALSE)
#plot_cells(monocle.object.all)

## add UMAP from Seurat
monocle.object.all@int_colData@listData$reducedDims@listData[["UMAP"]] <-seurat.object.all@reductions[["DIM_UMAP"]]@cell.embeddings 
plot_cells(monocle.object.all)
No trajectory to plot. Has learn_graph() been called yet?
cluster not found in colData(cds), cells will not be colored
cluster_cells() has not been called yet, can't color cells by cluster

## cluster
monocle.object.all = cluster_cells(monocle.object.all)

## plot clusters
plot_cells(monocle.object.all, color_cells_by="partition", group_cells_by="partition",  x = 2, y = 1)
No trajectory to plot. Has learn_graph() been called yet?
The `add` argument of `group_by()` is deprecated as of dplyr 1.0.0.
Please use the `.add` argument instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

## reduce partitions to 1
monocle.object.all@clusters$UMAP$partitions[monocle.object.all@clusters$UMAP$partitions == "2"] <- "1"

#map pseudotime
monocle.object.all = learn_graph(monocle.object.all, learn_graph_control=list(ncenter=500), use_partition = FALSE)

  |                                                                                                                             
  |                                                                                                                       |   0%
  |                                                                                                                             
  |=======================================================================================================================| 100%
plot_cells(monocle.object.all, color_cells_by="partition", group_cells_by="partition",  x = 2, y = 1)
`select_()` is deprecated as of dplyr 0.7.0.
Please use `select()` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
## a helper function to identify the root principal points:
## make cluster 2 the root
get_earliest_principal_node <- function(cds, time_bin="7"){
  cell_ids <- which(colData(cds)[, "seurat_clusters"] == time_bin)
  closest_vertex <-
  cds@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex
  closest_vertex <- as.matrix(closest_vertex[colnames(cds), ])
  root_pr_nodes <-
  igraph::V(principal_graph(cds)[["UMAP"]])$name[as.numeric(names
  (which.max(table(closest_vertex[cell_ids,]))))]
  
  root_pr_nodes
}

## calculate pseudotime
#monocle.object.all = order_cells(monocle.object.all, root_pr_nodes=get_earliest_principal_node(monocle.object.all))
monocle.object.all = order_cells(monocle.object.all)
Loading required package: shiny

Listening on http://127.0.0.1:4574

## plot
umap_pt <- plot_cells(monocle.object.all, color_cells_by = "pseudotime", label_cell_groups=FALSE, cell_size = 1, x = 2, y = 1, label_branch_points=FALSE, label_leaves=FALSE, label_groups_by_cluster=FALSE, label_roots = FALSE) +
  coord_fixed() +
  theme_void() +
  labs(title = "") +
  theme(plot.title = element_text(hjust = 0.5, size=20), legend.position="bottom", legend.title=element_text (size=20), legend.text=element_text(size=20)) + 
  guides(colour = guide_colourbar(barwidth = 10, barheight = 2, title = "Pseudotime"))

## view plot
umap_pt


## help was obtained from here
## https://github.com/satijalab/seurat/issues/1658

save

ggsave("../images_to_export/pt_all_UMAP_pt.png", plot = umap_pt, device = "png", path = NULL, scale = 1, width = 20, height = 20, units = "cm", dpi = 300, limitsize = TRUE)

gganimnate GIF of pseuodtime

#install.packages("gganimate")
library(gganimate)
#install.packages("gifski")
#install.packages("av")
#library(gifski)
#library(av)

## make dataframe for plotting
## extract data for GGplot version of this
df_animation <- as.data.frame(monocle.object.all@int_colData@listData$reducedDims@listData[["UMAP"]])
## add pt to this data frame:
pt_values <- as.data.frame(pseudotime(monocle.object.all, reduction_method = "UMAP"))
df_animation <- merge(df_animation, pt_values, by="row.names") 
rownames(df_animation) <- df_animation$Row.names
colnames(df_animation)[4] <- "pt"

## make the static plot
p <- ggplot(df_animation, aes(x = DIMUMAP_2, y = DIMUMAP_1, colour = pt)) +
  geom_point() +
  scale_colour_viridis_c(option = "plasma") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "none")
## view plot
plot(p)

## make animated plot
## make a category for animation
#df_animation$group <- cut(df_animation$pt, 15)

anim <- p +
  transition_time(pt) +
  shadow_mark()

animate(anim, height = 3, width = 3, units = "in", res = 150, bg = 'transparent')

Frame 1 (1%)
Frame 2 (2%)
Frame 3 (3%)
Frame 4 (4%)
Frame 5 (5%)
Frame 6 (6%)
Frame 7 (7%)
Frame 8 (8%)
Frame 9 (9%)
Frame 10 (10%)
Frame 11 (11%)
Frame 12 (12%)
Frame 13 (13%)
Frame 14 (14%)
Frame 15 (15%)
Frame 16 (16%)
Frame 17 (17%)
Frame 18 (18%)
Frame 19 (19%)
Frame 20 (20%)
Frame 21 (21%)
Frame 22 (22%)
Frame 23 (23%)
Frame 24 (24%)
Frame 25 (25%)
Frame 26 (26%)
Frame 27 (27%)
Frame 28 (28%)
Frame 29 (29%)
Frame 30 (30%)
Frame 31 (31%)
Frame 32 (32%)
Frame 33 (33%)
Frame 34 (34%)
Frame 35 (35%)
Frame 36 (36%)
Frame 37 (37%)
Frame 38 (38%)
Frame 39 (39%)
Frame 40 (40%)
Frame 41 (41%)
Frame 42 (42%)
Frame 43 (43%)
Frame 44 (44%)
Frame 45 (45%)
Frame 46 (46%)
Frame 47 (47%)
Frame 48 (48%)
Frame 49 (49%)
Frame 50 (50%)
Frame 51 (51%)
Frame 52 (52%)
Frame 53 (53%)
Frame 54 (54%)
Frame 55 (55%)
Frame 56 (56%)
Frame 57 (57%)
Frame 58 (58%)
Frame 59 (59%)
Frame 60 (60%)
Frame 61 (61%)
Frame 62 (62%)
Frame 63 (63%)
Frame 64 (64%)
Frame 65 (65%)
Frame 66 (66%)
Frame 67 (67%)
Frame 68 (68%)
Frame 69 (69%)
Frame 70 (70%)
Frame 71 (71%)
Frame 72 (72%)
Frame 73 (73%)
Frame 74 (74%)
Frame 75 (75%)
Frame 76 (76%)
Frame 77 (77%)
Frame 78 (78%)
Frame 79 (79%)
Frame 80 (80%)
Frame 81 (81%)
Frame 82 (82%)
Frame 83 (83%)
Frame 84 (84%)
Frame 85 (85%)
Frame 86 (86%)
Frame 87 (87%)
Frame 88 (88%)
Frame 89 (89%)
Frame 90 (90%)
Frame 91 (91%)
Frame 92 (92%)
Frame 93 (93%)
Frame 94 (94%)
Frame 95 (95%)
Frame 96 (96%)
Frame 97 (97%)
Frame 98 (98%)
Frame 99 (99%)
Frame 100 (100%)
Finalizing encoding... done!

## to change the resolution - https://stackoverflow.com/questions/49058567/define-size-for-gif-created-by-gganimate-change-dimension-resolution 

Save animation

anim_save("animated_UMAP_transparent_bg.gif", path = "../images_to_export/")
## extract pt values
pt_values <- as.data.frame(pseudotime(monocle.object.all, reduction_method = "UMAP"))

tenx.mutant.integrated <- AddMetaData(tenx.mutant.integrated, pt_values, "old_pt_values")

make composite pseudotime/ID figure

test <- df_umap_plot[which(df_umap_plot$cluster_colours_figure == "Male"), ]
ggplot(test, aes(x = DIMUMAP_2, y = DIMUMAP_1)) + 
  geom_point() +
  theme_void()

10. Save and Export

Save environment

```r
## This saves everything in the global environment for easy recall later
#save.image(file = \GCSKO_merge.RData\)
#load(file = \GCSKO_merge.RData\)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


Save object(s)

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyMgU2F2ZSBhbiBvYmplY3QgdG8gYSBmaWxlXG5zYXZlUkRTKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBmaWxlID0gXCIuLi9kYXRhX3RvX2V4cG9ydC90ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5SRFNcIilcbiMjIFJlc3RvcmUgdGhlIG9iamVjdFxuI3JlYWRSRFMoZmlsZSA9IFwiLi4vZGF0YV90b19leHBvcnQvdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXguUkRTXCIpXG5cbiMjIHNhdmUgaW50ZWdyYXRlZCBvYmplY3QgdG8gZmlsZVxuc2F2ZVJEUyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmaWxlID0gXCIuLi9kYXRhX3RvX2V4cG9ydC90ZW54Lm11dGFudC5pbnRlZ3JhdGVkLlJEU1wiKSBcbiMjIHJlc3RvcmUgdGhlIG9iamVjdFxuYGBgIn0= -->

```r
## Save an object to a file
saveRDS(tenx.mutant.integrated.sex, file = "../data_to_export/tenx.mutant.integrated.sex.RDS")
## Restore the object
#readRDS(file = "../data_to_export/tenx.mutant.integrated.sex.RDS")

## save integrated object to file
saveRDS(tenx.mutant.integrated, file = "../data_to_export/tenx.mutant.integrated.RDS") 
## restore the object

Appendix

Session Info

R version 4.0.3 (2020-10-10)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.7

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
 [1] stats4    parallel  grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] gganimate_1.0.7             shiny_1.5.0                 circlize_0.4.12             destiny_3.2.0              
 [5] monocle3_0.2.3.0            SingleCellExperiment_1.10.1 SummarizedExperiment_1.18.2 DelayedArray_0.14.1        
 [9] matrixStats_0.57.0          GenomicRanges_1.40.0        GenomeInfoDb_1.24.2         IRanges_2.22.2             
[13] S4Vectors_0.26.1            Biobase_2.48.0              BiocGenerics_0.34.0         Nebulosa_1.2.0             
[17] dplyr_1.0.2                 reshape2_1.4.4              Hmisc_4.4-1                 ggplot2_3.3.2              
[21] Formula_1.2-4               survival_3.2-7              lattice_0.20-41             gridExtra_2.3              
[25] cowplot_1.1.0               Seurat_3.2.2                viridis_0.5.1               viridisLite_0.3.0          
[29] patchwork_1.0.1            

loaded via a namespace (and not attached):
  [1] reticulate_1.18           ks_1.12.0                 tidyselect_1.1.0          htmlwidgets_1.5.2        
  [5] ranger_0.12.1             Rtsne_0.15                devtools_2.3.2            munsell_0.5.0            
  [9] codetools_0.2-16          ica_1.0-2                 future_1.19.1             gifski_0.8.6             
 [13] miniUI_0.1.1.1            withr_2.3.0               colorspace_1.4-1          knitr_1.30               
 [17] rstudioapi_0.11           ROCR_1.0-11               robustbase_0.93-7         vcd_1.4-8                
 [21] tensor_1.5                VIM_6.1.0                 TTR_0.24.2                listenv_0.8.0            
 [25] labeling_0.4.2            GenomeInfoDbData_1.2.3    polyclip_1.10-0           farver_2.0.3             
 [29] pheatmap_1.0.12           rprojroot_1.3-2           vctrs_0.3.4               generics_0.0.2           
 [33] xfun_0.18                 ggthemes_4.2.4            R6_2.5.0                  rsvd_1.0.3               
 [37] RcppEigen_0.3.3.7.0       bitops_1.0-6              spatstat.utils_1.17-0     assertthat_0.2.1         
 [41] promises_1.1.1            scales_1.1.1              nnet_7.3-14               gtable_0.3.0             
 [45] globals_0.13.1            processx_3.4.4            goftest_1.2-2             rlang_0.4.8              
 [49] scatterplot3d_0.3-41      GlobalOptions_0.1.2       splines_4.0.3             lazyeval_0.2.2           
 [53] hexbin_1.28.1             checkmate_2.0.0           BiocManager_1.30.10       yaml_2.2.1               
 [57] abind_1.4-5               crosstalk_1.1.0.1         backports_1.1.10          httpuv_1.5.4             
 [61] tools_4.0.3               usethis_1.6.3             ellipsis_0.3.1            RColorBrewer_1.1-2       
 [65] proxy_0.4-24              sessioninfo_1.1.1         ggridges_0.5.2            Rcpp_1.0.6               
 [69] plyr_1.8.6                base64enc_0.1-3           progress_1.2.2            zlibbioc_1.34.0          
 [73] purrr_0.3.4               RCurl_1.98-1.2            ps_1.4.0                  prettyunits_1.1.1        
 [77] rpart_4.1-15              deldir_0.1-29             pbapply_1.4-3             zoo_1.8-8                
 [81] haven_2.3.1               ggrepel_0.8.2             cluster_2.1.0             fs_1.5.0                 
 [85] magrittr_2.0.1            data.table_1.13.2         RSpectra_0.16-0           openxlsx_4.2.2           
 [89] lmtest_0.9-38             RANN_2.6.1                pcaMethods_1.80.0         mvtnorm_1.1-1            
 [93] fitdistrplus_1.1-1        pkgload_1.1.0             hms_0.5.3                 mime_0.9                 
 [97] evaluate_0.14             xtable_1.8-4              smoother_1.1              rio_0.5.16               
[101] jpeg_0.1-8.1              readxl_1.3.1              mclust_5.4.7              shape_1.4.5              
[105] testthat_2.3.2            compiler_4.0.3            tibble_3.0.4              KernSmooth_2.23-17       
[109] crayon_1.3.4              htmltools_0.5.1.1         mgcv_1.8-33               later_1.1.0.1            
[113] tidyr_1.1.2               tweenr_1.0.1              MASS_7.3-53               boot_1.3-25              
[117] leidenbase_0.1.2          car_3.0-10                Matrix_1.2-18             cli_2.1.0                
[121] igraph_1.2.6              forcats_0.5.0             pkgconfig_2.0.3           laeken_0.5.1             
[125] sp_1.4-4                  foreign_0.8-80            plotly_4.9.2.1            XVector_0.28.0           
[129] stringr_1.4.0             callr_3.5.1               digest_0.6.27             sctransform_0.3.1        
[133] RcppAnnoy_0.0.16          spatstat.data_1.4-3       cellranger_1.1.0          rmarkdown_2.5            
[137] leiden_0.3.3              htmlTable_2.1.0           uwot_0.1.8                DelayedMatrixStats_1.10.1
[141] curl_4.3                  ggplot.multistats_1.0.0   lifecycle_0.2.0           nlme_3.1-149             
[145] jsonlite_1.7.1            carData_3.0-4             desc_1.2.0                fansi_0.4.1              
[149] pillar_1.4.6              DEoptimR_1.0-8            fastmap_1.0.1             httr_1.4.2               
[153] pkgbuild_1.1.0            xts_0.12.1                glue_1.4.2                remotes_2.2.0            
[157] zip_2.1.1                 spatstat_1.64-1           png_0.1-7                 class_7.3-17             
[161] stringi_1.5.3             RcppHNSW_0.3.0            latticeExtra_0.6-29       memoise_1.1.0            
[165] irlba_2.3.3               e1071_1.7-4               future.apply_1.6.0       

Extras

Part 2 export data frames for Arthur

– Subset only 10X cells

– cluster 24 is predetermination cells – cluster 29 is post cells – cluster 36 is post cells

```r
## Subset 10X Dataset, cluster 24
## extract only cells in cluster 24
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = \seurat_clusters\, accept.value = c(\24\))
## get the names of the cells in cluster of interest
names_of_cells_in_cluster_24 <- colnames(seurat.object.subset@assays$RNA@counts)
## subset seurat
tenx_cluster_24 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_24)
## extract data
tenx_cluster_24_matrix_data <- as(as.matrix(GetAssayData(tenx_cluster_24, assay = \RNA\, slot = \data\)), 'sparseMatrix')
## extract counts
tenx_cluster_24_matrix_counts <- as(as.matrix(GetAssayData(tenx_cluster_24, assay = \RNA\, slot = \counts\)), 'sparseMatrix')
## extract meta data
## make big meta data dataframe
meta_df <- data.frame(tenx.mutant.integrated.sex@meta.data)
#meta_df <- data.frame(tenx.mutant.integrated@meta.data)
tenx_cluster_24_pd <- meta_df[which(rownames(meta_df) %in% colnames(tenx_cluster_24_matrix_counts)), ]
# save all 3 files
#write.csv(tenx_cluster_24_matrix_data, file = \~/data_to_export/tenx_cluster_24_matrix_data.csv\)
#write.csv(tenx_cluster_24_matrix_counts, file = \~/data_to_export/tenx_cluster_24_matrix_counts.csv\)
write.csv(tenx_cluster_24_pd, file = \~/data_to_export/tenx_cluster_24_pd.csv\)

## Subset 10X Dataset, cluster 29
# extract only cells in cluster 29
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = \seurat_clusters\, accept.value = c(\29\))
#get the names of the cells in cluster of interest
names_of_cells_in_cluster_29 <- colnames(seurat.object.subset@assays$RNA@counts)
# subset seurat
tenx_cluster_29 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_29)
# extract data
tenx_cluster_29_matrix_data <- as(as.matrix(GetAssayData(tenx_cluster_29, assay = \RNA\, slot = \data\)), 'sparseMatrix')
# extract counts
tenx_cluster_29_matrix_counts <- as(as.matrix(GetAssayData(tenx_cluster_29, assay = \RNA\, slot = \counts\)), 'sparseMatrix')
# extract meta data
tenx_cluster_29_pd <- meta_df[which(rownames(meta_df) %in% colnames(tenx_cluster_29_matrix_counts)), ]
# save all 3 files
#write.csv(tenx_cluster_29_matrix_data, file = \~/data_to_export/tenx_cluster_29_matrix_data.csv\)
#write.csv(tenx_cluster_29_matrix_counts, file = \~/data_to_export/tenx_cluster_29_matrix_counts.csv\)
write.csv(tenx_cluster_29_pd, file = \~/data_to_export/tenx_cluster_29_pd.csv\)

## Subset 10X Dataset, cluster 36
# extract only cells in cluster 36
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = \seurat_clusters\, accept.value = c(\36\))
#get the names of the cells in cluster of interest
names_of_cells_in_cluster_36 <- colnames(seurat.object.subset@assays$RNA@counts)
# subset seurat
tenx_cluster_36 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_36)
# extract data
tenx_cluster_36_matrix_data <- as(as.matrix(GetAssayData(tenx_cluster_36, assay = \RNA\, slot = \data\)), 'sparseMatrix')
# extract counts
tenx_cluster_36_matrix_counts <- as(as.matrix(GetAssayData(tenx_cluster_36, assay = \RNA\, slot = \counts\)), 'sparseMatrix')
# extract meta data
tenx_cluster_36_pd <- meta_df[which(rownames(meta_df) %in% colnames(tenx_cluster_36_matrix_counts)), ]
# save all 3 files
#write.csv(tenx_cluster_36_matrix_data, file = \~/data_to_export/tenx_cluster_36_matrix_data.csv\)
#write.csv(tenx_cluster_36_matrix_counts, file = \~/data_to_export/tenx_cluster_36_matrix_counts.csv\)
write.csv(tenx_cluster_36_pd, file = \~/data_to_export/tenx_cluster_36_pd.csv\)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### old code


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyMgb2xkIHRocmVzaG9sZHMgb24gZGF0YSB3aXRoIDI4XG4jcmVtb3ZlX2NlbGxzIDwtIHJvdy5uYW1lcyhkZl9zZXhfY2VsbF9lbWJlZGRpbmdzW3doaWNoKGRmX3NleF9jZWxsX2VtYmVkZGluZ3MkRElNVU1BUF8yIDwgMC4xICYgZGZfc2V4X2NlbGxfZW1iZWRkaW5ncyRESU1VTUFQXzEgPiAtMS4yKSwgXSlcbmBgYCJ9 -->

```r
## old thresholds on data with 28
#remove_cells <- row.names(df_sex_cell_embeddings[which(df_sex_cell_embeddings$DIMUMAP_2 < 0.1 & df_sex_cell_embeddings$DIMUMAP_1 > -1.2), ])

Publication Figure

Cowplot(plot_grid), patchwork(wrap_plots), and ggpubr can all allow multiple plots to be plotted together.

## A
# umap_id_pt
## B
# marker gene expression
## C
# Mutant gene expression
## D
# Modules

#Figure_A <- grid.arrange(arrangeGrob(QC_composite_plot, QC_mito_violin, QC_mito_graph, QC_by_genotype, mapping_rate_plot), nrow=3), nrow=2, heights=c(10,2))

## cowplot method
## can use this for labels: toupper(letters)[1:10]

## C. Mutant genes
mutant_genes_figure <- plot_grid(
  ## marker genes starts
                              list_of_density_plots[[8]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=7)) + labs(title = paste("Fam-b2 (Ring)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots[[5]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=7)) + labs(title = paste("MSP8 (Asexual)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots[[4]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=7)) + labs(title = paste("MSP1 (Schizont)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots[[3]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=7)) + labs(title = paste("AP2G (Commitment)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30)) )+ guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots[[1]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=7)) + 
  labs(title = paste("CCP2 (Female)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots[[2]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=7)) + labs(title = paste("MG1 (Male)")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
  ## mutant genes starts
                            list_of_density_plots_mutant_genes[[1]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("gd1")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[2]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("md1")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[3]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("md2")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[4]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("md3")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30)) )+ guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[5]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("md4")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[6]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("md5")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[7]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("fd1")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[8]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("fd2")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[9]] + coord_fixed() + theme_void() + theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("fd3")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
                             list_of_density_plots_mutant_genes[[10]] + coord_fixed() + theme_void()+ theme(plot.title = element_text(hjust = 0.5), legend.text = element_text(size = 8), text=element_text(size=9)) + labs(title = paste("fd4")) + scale_colour_gradientn(colours=c("#DCDCDC", plasma(30))) + guides(colour = guide_colourbar(barwidth = 0.5, barheight = 4.5, title = "")),
  labels = c(toupper(letters)[2:17]), 
  label_size = 12, 
  nrow = 4)
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Figure_publication <- plot_grid(umap_id_pt, 
                                mutant_genes_figure,
                                ## add empty plot to give spacing
                                ggplot() + theme_void(),
                                labels = c('A'), 
                                label_size = 12, 
                                ncol = 2, 
                                nrow=2, 
                                rel_heights = c(1, 1, 4), 
                                rel_widths = c(1, 2, 3))

Figure_publication

save

ggsave("../images_to_export/Figure_C.png", plot = Figure_publication, device = "png", path = NULL, scale = 1, width = 21, height = 29.7, units = "cm", dpi = 300, limitsize = TRUE)

save and export individual plots so it can be stitched with

LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSguLi9HQ1NLT19sb2dvLmpwZyl7d2lkdGg9MzAwcHh9ICAKICBNZXJnaW5nIFNtYXJ0LXNlcTIgYW5kIDEwWCBEYXRhc2V0cwphdXRob3I6ICJbQW5kcmV3IFJ1c3NlbGxdKGh0dHBzOi8vYWpjcnVzc2VsbC53aXhzaXRlLmNvbS9teXNpdGUvYWJvdXQpIgppbnN0aXR1dGU6IFdlbGxjb21lIFNhbmdlciBJbnN0aXR1dGUKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpLCAiJUIgJWQsICVZIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgI3RvY19mbG9hdDogeWVzCiAgICBkZl9wcmludDogcGFnZWQKLS0tCioqKgojIDEuIEludHJvZHVjdGlvbiBhbmQgQWltcyB7LnRhYnNldH0KCldlIGhhdmUgcXVhbGl0eS1jb250cm9sbGVkIHRoZSAxMFggZGF0YSBhbmQgdGhlIFNTMiBkYXRhIGFuZCBub3cgYXJlIGxlZnQgd2l0aCB0aGUgZm9sbG93aW5nIG9iamVjdHM6CgoxMFggNUsgZGF0YSAtIHBiX3NleF9maWx0ZXJlZAoKMTBYIDMwSyBkYXRhIC0gcGJfMzBrX3NleF9maWx0ZXJlZCAKClNTMiBtdXRhbnQgZGF0YSAtIHNzMl9tdXRhbnRzX2ZpbmFsCgojIDIuIFJlYWQgaW4gdGhlIGRhdGEgIHsudGFic2V0fQoKIyMjIExvYWQvSW5zdGFsbCB0aGUgUmVxdWlyZWQgUGFja2FnZXMKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG8gPSBGQUxTRX0KIyMgQ1JBTiBwYWNrYWdlcwoKIyMgUGF0aHdvcmsgaXMgbmVlZGVkIHRvIHN0aWNoIHBsb3RzIHRvZ2V0aGVyIHVzaW5nICcrJwppZihyZXF1aXJlKCJwYXRjaHdvcmsiLCBxdWlldGx5ID0gVFJVRSkpewogICAgcHJpbnQoInBhdGNod29yayBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBwYXRjaHdvcmsiKQogICAgaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKICAgIGlmKHJlcXVpcmUocGF0Y2h3b3JrKSl7CiAgICAgICAgcHJpbnQoInBhdGNod29yayBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIHBhdGNod29yayIpCiAgICB9Cn0KCiMjIHZpcmlkaXMgYWxsb3dzIGRpZmZlcmVudCBjb2xvdXJzIHRvIGJlIGFkZGVkIHRvIHBsb3RzCmlmKHJlcXVpcmUoInZpcmlkaXMiLCBxdWlldGx5ID0gVFJVRSkpewogICAgcHJpbnQoInZpcmlkaXMgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgdmlyaWRpcyIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJ2aXJpZGlzIikKICAgIGlmKHJlcXVpcmUodmlyaWRpcykpewogICAgICAgIHByaW50KCJ2aXJpZGlzIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgdmlyaWRpcyIpCiAgICB9Cn0KCiMjIFNldXJhdCBpcyBuZWVkZWQgZm9yIG1vc3Qgb2YgdGhpcyBzY3JpcHQKaWYocmVxdWlyZSgiU2V1cmF0IiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJTZXVyYXQgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgU2V1cmF0IikKICAgIGluc3RhbGwucGFja2FnZXMoIlNldXJhdCIpCiAgICBpZihyZXF1aXJlKFNldXJhdCkpewogICAgICAgIHByaW50KCJTZXVyYXQgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBTZXVyYXQiKQogICAgfQp9CgojIyBjb3dwbG90IGlzIG5lZWRlZCBmb3IgcGxvdHMgaW4gdGhpcyBzY3JpcHQKaWYocmVxdWlyZSgiY293cGxvdCIpKXsKICAgIHByaW50KCJjb3dwbG90IGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGNvd3Bsb3QiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpCiAgICBpZihyZXF1aXJlKGNvd3Bsb3QpKXsKICAgICAgICBwcmludCgiY293cGxvdCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGNvd3Bsb3QiKQogICAgfQp9CgojIyBncmlkRXh0cmEgaXMgbmVlZGVkIGZvciBncmlkIGdyYXBoaWNzIHRvIHBsb3QgbXVsdGlwbGUgcGxvdHMgaW4gdGhlIHNhbWUgdmlldwppZihyZXF1aXJlKCJncmlkRXh0cmEiKSl7CiAgICBwcmludCgiZ3JpZEV4dHJhIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGdyaWRFeHRyYSIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJncmlkRXh0cmEiKQogICAgaWYocmVxdWlyZShncmlkRXh0cmEpKXsKICAgICAgICBwcmludCgiZ3JpZEV4dHJhIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgZ3JpZEV4dHJhIikKICAgIH0KfQoKIyMgZ3JpZCBpcyBuZWVkZWQgZm9yIGdyaWQuYXJyYW5nZSBmdW5jdGlvbiB0byBjaGFuZ2Ugc2l6ZSBvZiB0aXRsZQppZihyZXF1aXJlKCJncmlkIikpewogICAgcHJpbnQoImdyaWQgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgZ3JpZCIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJncmlkIikKICAgIGlmKHJlcXVpcmUoZ3JpZCkpewogICAgICAgIHByaW50KCJncmlkIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgZ3JpZCIpCiAgICB9Cn0KCiMjZm9yIGRvaW5nIGJ1bGsgY29ycmVsYXRpb24gY2FsY3VsYXRpb25zCmlmKHJlcXVpcmUoIkhtaXNjIikpewogICAgcHJpbnQoIkhtaXNjIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIEhtaXNjIikKICAgIGluc3RhbGwucGFja2FnZXMoIkhtaXNjIikKICAgIGlmKHJlcXVpcmUoSG1pc2MpKXsKICAgICAgICBwcmludCgiSG1pc2MgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBIbWlzYyIpCiAgICB9Cn0KCiMjIHJlc2hhcGUyIHRvIG1lbHQgZGF0YWZyYW1lcyBmb3IgcGxvdHRpbmc6CmlmKHJlcXVpcmUoInJlc2hhcGUyIikpewogICAgcHJpbnQoInJlc2hhcGUyIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIHJlc2hhcGUyIikKICAgIGluc3RhbGwucGFja2FnZXMoInJlc2hhcGUyIikKICAgIGlmKHJlcXVpcmUocmVzaGFwZTIpKXsKICAgICAgICBwcmludCgicmVzaGFwZTIgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCByZXNoYXBlMiIpCiAgICB9Cn0KCiMjIHRvIHdvcmsgd2l0aCBkYXRhIGZyYW1lczoKaWYocmVxdWlyZSgiZHBseXIiKSl7CiAgICBwcmludCgiZHBseXIgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgZHBseXIiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQogICAgaWYocmVxdWlyZShkcGx5cikpewogICAgICAgIHByaW50KCJkcGx5ciBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGRwbHlyIikKICAgIH0KfQoKIyMgbm9uLUNSQU4gcGFja2FnZXMKCiMjIHRvIG1ha2UgZGVuc2l0eSBwbG90cyBzaG93aW5nIGdlbmUgZXhwcmVzc2lvbgppZihyZXF1aXJlKCJOZWJ1bG9zYSIpKXsKICAgIHByaW50KCJOZWJ1bG9zYSBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBOZWJ1bG9zYSIpCiAgICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInBvd2VsbGdlbm9taWNzbGFiL05lYnVsb3NhIikKICAgIGlmKHJlcXVpcmUoTmVidWxvc2EpKXsKICAgICAgICBwcmludCgiTmVidWxvc2EgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBOZWJ1bG9zYSIpCiAgICB9Cn0KCiMjIG1vbm9jbGUzIHRvIGNhbGN1bGF0ZSBwc2V1ZG90aW1lOgppZihyZXF1aXJlKCJtb25vY2xlMyIpKXsKICAgIHByaW50KCJtb25vY2xlMyBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJQbGVhc2UgaW5zdGFsbCBtb25vY2xlMyAoaHR0cHM6Ly9jb2xlLXRyYXBuZWxsLWxhYi5naXRodWIuaW8vbW9ub2NsZTMvZG9jcy9pbnN0YWxsYXRpb24vKSIpCn0KCiMjIHNldCB0aGUgc2VlZCBmb3IgYm90aCB0aGUgbWl4dHVyZSBtb2RlbHMgYW5kIGFsc28gZm9yIHRoZSBzYW1wbGUgZnVuY3Rpb24gbGF0ZXIgb246CnNldC5zZWVkKC05MjQ5NykKYGBgCgojIyMgUmVhZCBpbiB0aGUgRGF0YQoKc2NyZWVuIGhpdHMKYGBge3J9CiMjIEVESVQgLSBjaGFuZ2UgdGhpcyB0byB0aGUgZXhjZWwgdGFibGUgb25jZSB3ZSBoYXZlIGl0IGZpbmFsaXplZCBmb3IgdGhlIHNjcmVlbgpzY3JlZW5faGl0cyA8LSBjKCJQQkFOS0EtMDUxNjMwMCIsCiJQQkFOS0EtMTIxNzcwMCIsCiJQQkFOS0EtMDQwOTEwMCIsCiJQQkFOS0EtMTAzNDMwMCIsCiJQQkFOS0EtMTQzNzUwMCIsCiJQQkFOS0EtMDgyNzUwMCIsCiJQQkFOS0EtMDgyNDMwMCIsCiJQQkFOS0EtMTQyNjkwMCIsCiJQQkFOS0EtMDEwNTMwMCIsCiJQQkFOS0EtMDkyMTEwMCIsCiJQQkFOS0EtMTAwMjQwMCIsCiJQQkFOS0EtMDgyOTQwMCIsCiJQQkFOS0EtMTM0NzIwMCIsCiJQQkFOS0EtMDgyODAwMCIsCiJQQkFOS0EtMDkwMjMwMCIsCiJQQkFOS0EtMTQxODEwMCIsCiJQQkFOS0EtMTQzNTIwMCIsCiJQQkFOS0EtMTQ1NDgwMCIsCiJQQkFOS0EtMDcxMjMwMCIsCiJQQkFOS0EtMDQxMDUwMCIsCiJQQkFOS0EtMTE0NDgwMCIsCiJQQkFOS0EtMTIzMTYwMCIsCiJQQkFOS0EtMDUwMzIwMCIsCiJQQkFOS0EtMDMwODkwMCIsCiJQQkFOS0EtMTIxNDcwMCIsCiJQQkFOS0EtMDcwOTkwMCIsCiJQQkFOS0EtMDMxMTkwMCIsCiJQQkFOS0EtMDcxNjUwMCIsCiJQQkFOS0EtMTQ0NzkwMCIsCiJQQkFOS0EtMDEwMjIwMCIsCiJQQkFOS0EtMDcxMzUwMCIsCiJQQkFOS0EtMDEwMjQwMCIsCiJQQkFOS0EtMTMwMjcwMCIsCiJQQkFOS0EtMTIzNTkwMCIsCiJQQkFOS0EtMDQwMTEwMCIsCiJQQkFOS0EtMDQxMzQwMCIsCiJQQkFOS0EtMTEyNjkwMCIsCiJQQkFOS0EtMTQyNTkwMCIsCiJQQkFOS0EtMDQxODMwMCIsCiJQQkFOS0EtMTQ2NDYwMCIsCiJQQkFOS0EtMDgwNjAwMCIpCmBgYAoKbG9hZCBpbiBkYXRhc2V0cwpgYGB7cn0KIyMgbG9hZCB0aGUgMTBYIGRhdGFzZXQKcGJfc2V4X2ZpbHRlcmVkIDwtIHJlYWRSRFMoIi4uL2RhdGFfdG9fZXhwb3J0L3BiX3NleF9maWx0ZXJlZC5SRFMiKQojIyBsb2FkIHRoZSBTUzIgZGF0YXNldApzczJfbXV0YW50c19maW5hbCA8LSByZWFkUkRTKCIuLi9kYXRhX3RvX2V4cG9ydC9zczJfbXV0YW50c19maW5hbC5SRFMiKQoKIyMgaW5zcGVjdApwYXN0ZSgiMTB4IGRhdGFzZXQiKQpwYl9zZXhfZmlsdGVyZWQKcGFzdGUoIlNtYXJ0LXNlcTIgZGF0YXNldCIpCnNzMl9tdXRhbnRzX2ZpbmFsCnBhc3RlKCJUaGUgY29tcG9zaXRpb24gb2YgdGhlIFNtYXJ0LXNlcTIgZGF0YXNldCBpczoiKQp0YWJsZShzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEkZ2Vub3R5cGUpCmBgYAoKIyAzLiBNZXJnaW5nIHRoZSBTbWFydC1zZXEyIGFuZCAxMFggRGF0YSB7LnRhYnNldH0KCiMjIyBQcmVwYXJlIGRhdGEKCmBgYHtyIGludGVncmF0aW9uIDEweCBzZXR1cH0KIyMgZXh0cmFjdCAxMHggZGF0YQp0ZW54XzVrX2NvdW50cyA8LSBhcy5tYXRyaXgocGJfc2V4X2ZpbHRlcmVkQGFzc2F5cyRSTkFAY291bnRzKQp0ZW54XzVrX3BoZW5vIDwtIHBiX3NleF9maWx0ZXJlZEBtZXRhLmRhdGEKCiMjIENyZWF0ZSBmcmVzaCBvYmplY3QKdGVueF81a19jb3VudHNfdG9faW50ZWdyYXRlIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSB0ZW54XzVrX2NvdW50cywgbWV0YS5kYXRhID0gdGVueF81a19waGVubywgbWluLmNlbGxzID0gMCwgbWluLmZlYXR1cmVzID0gMCwgcHJvamVjdCA9ICJHQ1NLTyIpCgojIyBhZGQgZXhwZXJpbWVudCBtZXRhIGRhdGEKdGVueF81a19jb3VudHNfdG9faW50ZWdyYXRlQG1ldGEuZGF0YSRleHBlcmltZW50IDwtICJ0ZW54XzVrIgoKIyMgaW5zcGVjdAp0ZW54XzVrX2NvdW50c190b19pbnRlZ3JhdGUKYGBgCgpXZSBuZWVkIHRvIG1ha2Ugc3VyZSB0aGUgbXV0YW50IGRhdGEgaXMgY29tcGF0aWJsZSB3aXRoIHRoZSAxMFggZGF0YS4gdGhlIDEwWCBkYXRhIGhhcyBmZXdlciBnZW5lcyByZXByZXNlbnRlZCBzbyB3ZSBuZWVkIHRvIGZpbmQgdGhlIGludGVyc2VjdCBvZiB0aGUgdHdvIGJlZm9yZSBpbnRlZ3JhdGlvbi4KYGBge3IgaW50ZWdyYXRpb24gc3MyIHNldHVwfQojIyBleHRyYWN0IFNTMiBkYXRhIAptdXRhbnRfY291bnRzX2Zvcl9pbnRlZ3JhdGlvbiA8LSBhcy5tYXRyaXgoc3MyX211dGFudHNfZmluYWxAYXNzYXlzJFJOQUBjb3VudHMpCm11dGFudF9waGVub19mb3JfaW50ZWdyYXRpb24gPC0gc3MyX211dGFudHNfZmluYWxAbWV0YS5kYXRhCgojIyBjaGFuZ2UgY291bnRzIHNvIHRoZSA6clJOQSBhbmQgOnRSTkEgYXJlIG5vdCB0aGVyZToKcm93bmFtZXMobXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pIDwtIGdzdWIoIjpuY1JOQSIsICIiLCBnc3ViKCI6clJOQSIsICIiLCBnc3ViKCI6dFJOQSIsICIiLCByb3duYW1lcyhtdXRhbnRfY291bnRzX2Zvcl9pbnRlZ3JhdGlvbikpKSkKCiMjIGNoYW5nZSB0aGUgZ2VuZSBuYW1lcyBzbyB0aGF0IHRoZXkgYXJlIC0gcmF0aGVyIHRoYW4gXzoKcm93bmFtZXMobXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pIDwtIGdzdWIoIl8iLCAiLSIsIHJvd25hbWVzKG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uKSkKCiMjIGNhbGN1bGF0ZSBob3cgbWFueSBvZiB0aGUgZ2VuZXMgb3ZlcmxhcCAtIDEweCBkb2VzIHN0YXJ0IG91dCB3aXRoIDUwOTggdnMgNTI0NQpnZW5lc19pbl90ZW54X2RhdGFzZXQgPC0gaW50ZXJzZWN0KHJvd25hbWVzKHRlbnhfNWtfY291bnRzKSwgcm93bmFtZXMobXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pKQojIyBwcmludCBudW1iZXIgb2YgZ2VuZXMgdGhhdCBvdmVybGFwCmRpbShtdXRhbnRfY291bnRzX2Zvcl9pbnRlZ3JhdGlvbikKIyMgc3Vic2V0IHRoZSBtdXRhbnQgY291bnRzIHRvIGNvbnRhaW4gb25seSAxMHggZ2VuZXMKbXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24gPC0gbXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb25bd2hpY2gocm93bmFtZXMobXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pICVpbiUgZ2VuZXNfaW5fdGVueF9kYXRhc2V0KSwgXQojIyBwcmludCByZXN1bHQgb2YgZ2VuZXMgdGhhdCBvdmVybGFwCmRpbShtdXRhbnRfY291bnRzX2Zvcl9pbnRlZ3JhdGlvbikKCiMjIG1ha2UgU2V1cmF0IG9iamVjdDoKR0NTS09fbXV0YW50cyA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gbXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24sIG1ldGEuZGF0YSA9IG11dGFudF9waGVub19mb3JfaW50ZWdyYXRpb24sIG1pbi5jZWxscyA9IDAsIG1pbi5mZWF0dXJlcyA9IDAsIHByb2plY3QgPSAiR0NTS08iKQoKIyMgYWRkIGV4cGVyaW1lbnQgbWV0YSBkYXRhCkdDU0tPX211dGFudHNAbWV0YS5kYXRhJGV4cGVyaW1lbnQgPC0gIm11dGFudHMiCgojIyBpbnNwZWN0CkdDU0tPX211dGFudHMKYGBgCgpgYGB7cn0KIyMgZG91YmxlIGNoZWNrIHRoYXQgdGhpcyBpcyB0aGUgc2FtZSBudW1iZXIgb2YgZ2VuZXMKIyMgc3Vic2V0IGNvdW50cyBzbyB0aGF0IG9ubHkgZ2VuZXMgcmVwcmVzZW50ZWQgaW4gdGhlIG90aGVyIHR3byBvYmplY3RzIGFyZSB0aGVyZToKbGVuZ3RoKGludGVyc2VjdChyb3duYW1lcyh0ZW54XzVrX2NvdW50cyksIHJvd25hbWVzKG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uKSkpCmBgYAoKY3JlYXRlIGxpc3QgYW5kIG5vcm1hbGlzZToKYGBge3IgaW50ZWdyYXRpb24gbm9ybWFsaXNlfQojIyBtYWtlIGxpc3QKdGVueC5tdXRhbnQubGlzdCA8LSBsaXN0KHRlbnhfNWtfY291bnRzX3RvX2ludGVncmF0ZSwgR0NTS09fbXV0YW50cykKCiMjIHByZXBhcmUgZGF0YQpmb3IgKGkgaW4gMTpsZW5ndGgodGVueC5tdXRhbnQubGlzdCkpIHsKICAgIHRlbngubXV0YW50Lmxpc3RbW2ldXSA8LSBOb3JtYWxpemVEYXRhKHRlbngubXV0YW50Lmxpc3RbW2ldXSwgdmVyYm9zZSA9IEZBTFNFKQogICAgdGVueC5tdXRhbnQubGlzdFtbaV1dIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHRlbngubXV0YW50Lmxpc3RbW2ldXSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCAKICAgICAgICBuZmVhdHVyZXMgPSAyMDAwLCB2ZXJib3NlID0gRkFMU0UpCn0KYGBgCgojIyMgSW50ZWdyYXRlIG9iamVjdHMKCmBgYHtyIGludGVncmF0aW9ufQojIyBGaW5kIGFuY2hvcnMKdGVueC5tdXRhbnQuYW5jaG9ycyA8LSBGaW5kSW50ZWdyYXRpb25BbmNob3JzKG9iamVjdC5saXN0ID0gdGVueC5tdXRhbnQubGlzdCwgZGltcyA9IDE6MjEsIHZlcmJvc2UgPSBGQUxTRSkKCiMjIEludGVncmF0ZSBkYXRhCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gSW50ZWdyYXRlRGF0YShhbmNob3JzZXQgPSB0ZW54Lm11dGFudC5hbmNob3JzLCBkaW1zID0gMToyMSwgdmVyYm9zZSA9IEZBTFNFLCBmZWF0dXJlcy50by5pbnRlZ3JhdGUgPSBnZW5lc19pbl90ZW54X2RhdGFzZXQpCmBgYAoKIyA0LiBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gey50YWJzZXR9CgojIyMgUENBCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDV9CiMjIE1ha2UgdGhlIGRlZmF1bHQgYXNzYXkgaW50ZWdyYXRlZApEZWZhdWx0QXNzYXkodGVueC5tdXRhbnQuaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCgojIyBSdW4gdGhlIHN0YW5kYXJkIHdvcmtmbG93IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjbHVzdGVyaW5nCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gU2NhbGVEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQsIHZlcmJvc2UgPSBGQUxTRSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBSdW5QQ0EodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbnBjcyA9IDMwLCB2ZXJib3NlID0gRkFMU0UpCgojIyBpbnNwZWN0IFBDcwpFbGJvd1Bsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbmRpbXMgPSAzMCwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKIyMjIFVNQVAKCiMjIyMgSW5pdGlhbCBVTUFQCgpSdW4gaW5pdGFsIFVNQVAKYGBge3J9CiMjIFJ1biBVTUFQCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gUnVuVU1BUCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6OCwgbi5uZWlnaGJvcnMgPSA1MCwgc2VlZC51c2UgPSAxMjM0LCBtaW4uZGlzdCA9IDAuNSwgcmVwdWxzaW9uLnN0cmVuZ3RoID0gMC4wNSkKYGBgCgpTZWUgZGlzdHJpYnV0aW9uIGJ5OiBhbHRvZ2V0aGVyLCBleHBlcmltZW50LCBhbmQgbXV0YW50IElECmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNn0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgcHQuc2l6ZSA9IDAuMDEpCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJleHBlcmltZW50IiwgcHQuc2l6ZSA9IDAuMDEpCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjAxKQpgYGAKCiMjIyMgT3B0aW1pc2VkIFVNQVAKQWZ0ZXIgb3B0aW1pc2F0aW9uLCB0aGUgZm9sbG93aW5nIFVNQVAgY2FuIGJlIGNhbGN1bGF0ZWQ6CmBgYHtyIHVtYXAgcnVuIDIsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQojIyBSdW4gb3B0aW1pc2VkIFVNQVAKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjQsIHJlcHVsc2lvbi5zdHJlbmd0aCA9IDAuMDMsIGxvY2FsLmNvbm5lY3Rpdml0eSA9IDE1MCkKYGBgCgpgYGB7ciB1bWFwIHZpc3VhbGlzZSAyfQojIyBwbG90CmRwMSA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBGQUxTRSwgcHQuc2l6ZSA9IDAuMDUsIGRpbXMgPSBjKDIsMSksIGdyb3VwLmJ5ID0gImV4cGVyaW1lbnQiKSArIAogICMjIGZpeCB0aGUgYXhpcwogIGNvb3JkX2ZpeGVkKCkgKyAKICAjIyByZXZlcnNlIHRoZSBzY2FsZQogIHNjYWxlX3lfcmV2ZXJzZSgpCgojIyB2aWV3CmRwMQpgYGAKCk5vdyBzdG9yZSB0aGVzZSByZXZlcnNlZCBlbWJlZGRpbmdzIGluIGEgbmV3IHNsb3QKYGBge3J9CiMjIGV4dHJhY3QgdGhlIGNlbGwgZW1iZWRkaW5ncyBmcm9tIHRoZSBVTUFQCm1kcyA8LSBhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWRAcmVkdWN0aW9ucyR1bWFwQGNlbGwuZW1iZWRkaW5ncykKCiMjIGNoYW5nZSB0aGUgY29vcmRpbmF0ZXMgb2YgVU1BUCAxIHNvIHRoZXkgYXJlIHJldmVyc2VkCm1kcyRVTUFQXzEgPC0gLW1kcyRVTUFQXzEKCiMjIGNoYW5nZSBuYW1lcyBvZiB0aGUgY29scyAKY29sbmFtZXMobWRzKSA8LSBwYXN0ZTAoIkRJTV9VTUFQXyIsIDE6MikKCiMjIG1ha2UgaW50byBhIG1hdHJpeCBzbyB0aGF0IGl0IGNhbiBiZSBzYXZlZCBpbiBTZXVyYXQKbWRzIDwtIGFzLm1hdHJpeChtZHMpCgojIyBzdG9yZSB0aGlzIG9wdGltc2VkIFVNQVAgaW4gYSBjdXN0b20gZGltIHNsb3QKdGVueC5tdXRhbnQuaW50ZWdyYXRlZFtbIkRJTV9VTUFQIl1dIDwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBtZHMsIGtleSA9ICJESU1fVU1BUF8iLCBhc3NheSA9IERlZmF1bHRBc3NheSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkKSkKCiMjIGNoZWNrCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IEZBTFNFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyBjb29yZF9maXhlZCgpCmBgYAoKIyA1LiBDbHVzdGVyaW5nIHsudGFic2V0fSAKCiMjIyBHZW5lcmF0ZSBjbHVzdGVycwpSZWNsdXN0ZXIgZGF0YXNldCBub3cgdGhhdCBpdCBpcyBpbnRlZ3JhdGVkLiAKV2Ugd2lsbCBjbHVzdGVyIHdpdGggYSBudW1iZXIgb2YgcmVzb2x1dGlvbnMgdG8gYmVnaW4gd2l0aCB0byBzZWUgaG93IHRoaXMgYWZmZWN0cyB0aGUgbnVtYmVyIGFuZCBuYXR1cmUgb2YgdGhlIGNsdXN0ZXJzLiAKYGBge3J9CiMjIGNvcHkgb2xkIGNsdXN0ZXJzCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkUk5BX3Nubl9yZXMuMSwgY29sLm5hbWUgPSAicHJlX2ludGVncmF0aW9uX2NsdXN0ZXJzIikKCiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBsb3cgcmVzb2x1dGlvbgojIyAxCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxNSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDEsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBnZW5lcmF0ZSBuZXcgY2x1c3RlcnMgYXQgbG93IHJlc29sdXRpb24KIyMgMS4yCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxNSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDEuMiwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKCiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBsb3cgcmVzb2x1dGlvbgojIyAxLjUKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSAxOjE1KQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gMS41LCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQoKIyMgZ2VuZXJhdGUgbmV3IGNsdXN0ZXJzIGF0IG1pZCByZXNvbHV0aW9uCiMjIDIKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSAxOjE1KQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gMiwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKCiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBoaWdoIHJlc29sdXRpb24KIyMgNAp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IDE6MTUpCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZENsdXN0ZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlc29sdXRpb24gPSA0LCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQoKIyMgcHJpbnQgaWRlbnRpdGllcwojaGVhZChJZGVudHModGVueC5tdXRhbnQuaW50ZWdyYXRlZCksIDEwKQpgYGAKIyMjIEluc3BlY3QgY2x1c3RlcnMgYXQgZGlmZmVyZW50IHJlc29sdXRpb25zCgojIyMjIHJlc29sdXRpb24gPSAxCgpWaWV3CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNX0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEiKSArIGNvb3JkX2ZpeGVkKCkgCmBgYAoKTWFrZSBpbmRpdmlkdWFsIHBsb3RzIGhpZ2hsaWdodGluZyB3aGVyZSBjZWxscyBpbiBlYWNoIGNsdXN0ZXIgZmFsbApgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyBmb3IgbG9vcCB3aGljaCB0YWtlcyBlYWNoIGNsdXN0ZXIgYW5kIG1ha2VzIGEgbGlzdCBvZiBjZWxscyBhbmQgdGhlbiBwbG90cyBhIGhpZ2hsaWdodGVkIHBsb3QgYW5kIGFkZHMgaXQgdG8gYSBsaXN0CgojIyBtYWtlIGEgYmxhbmsgbGlzdApsaXN0X1VNQVBzX2J5X2NsdXN0ZXIgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEpKSkKCiMjIGZvciBsb29wCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xID09IGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMSlbaV0pLCBdKQogIHVhbXBfcGxvdCA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gbGlzdF9vZl9jZWxscywgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKwogICAgIyMgZml4IGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImNsdXN0ZXIiLCBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEpW2ldKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVhbXBfcGxvdAp9CgojIyBjaGVjayBudW1iZXIgb2YgY2x1c3RlcnMKI2xlbmd0aChsaXN0X1VNQVBzX2J5X2NsdXN0ZXIpCmBgYAoKcGxvdApgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KIyMgdGhpcyBmdW5jdGlvbiB3cml0ZXMgdGhlIG5leHQgYml0IG9mIGNvZGUgZm9yIHlvdQojIyBwdXQgaXQgaW50byB0aGUgY29uc29sZSBhbmQgcGFzdGUgdGhlIHJlc3BvbnNlCiNwbG90eSA8LSBjKCkKI2ZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkpewojICBwbG90eSA8LSBwYXN0ZTAocGxvdHksICJsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWyIsIGksICJdXSIsICIgKyAiKQojfQoKIyMgcGxvdApsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s2XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s5XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEwXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzExXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEyXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEzXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE0XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE2XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE3XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE5XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIwXV0KYGBgCgojIyMjIHJlc29sdXRpb24gPSAxLjIKClZpZXcKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA1fQojIyBQbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjA1LCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMS4yIikgKyBjb29yZF9maXhlZCgpIApgYGAKCk1ha2UgaW5kaXZpZHVhbCBwbG90cyBoaWdobGlnaHRpbmcgd2hlcmUgY2VsbHMgaW4gZWFjaCBjbHVzdGVyIGZhbGwKYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyMgZm9yIGxvb3Agd2hpY2ggdGFrZXMgZWFjaCBjbHVzdGVyIGFuZCBtYWtlcyBhIGxpc3Qgb2YgY2VsbHMgYW5kIHRoZW4gcGxvdHMgYSBoaWdobGlnaHRlZCBwbG90IGFuZCBhZGRzIGl0IHRvIGEgbGlzdAoKIyMgbWFrZSBhIGJsYW5rIGxpc3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjIpKSkKCiMjIGZvciBsb29wCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEuMikpKXsKICAjIyBtYWtlIGEgbGlzdCBvZiBjZWxscwogIGxpc3Rfb2ZfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEuMiA9PSBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEuMilbaV0pLCBdKQogIHVhbXBfcGxvdCA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gbGlzdF9vZl9jZWxscywgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKwogICAgIyMgZml4IGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImNsdXN0ZXIiLCBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEuMilbaV0pKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgIyMgYWRkIHRvIHRoZSBsaXN0CiAgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1tpXV0gPC0gdWFtcF9wbG90Cn0KCiMjIGNoZWNrIG51bWJlciBvZiBjbHVzdGVycwpsZW5ndGgobGlzdF9VTUFQc19ieV9jbHVzdGVyKQpgYGAKCnBsb3QKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMjIHRoaXMgZnVuY3Rpb24gd3JpdGVzIHRoZSBuZXh0IGJpdCBvZiBjb2RlIGZvciB5b3UKIyMgcHV0IGl0IGludG8gdGhlIGNvbnNvbGUgYW5kIHBhc3RlIHRoZSByZXNwb25zZQojcGxvdHkgPC0gYygpCiNmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKXsKIyAgcGxvdHkgPC0gcGFzdGUwKHBsb3R5LCAibGlzdF9VTUFQc19ieV9jbHVzdGVyW1siLCBpLCAiXV0iLCAiICsgIikKI30KCiMjIHBsb3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s0XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s3XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMl1dCmBgYAoKIyMjIyByZXNvbHV0aW9uID0gMS41CgpgYGB7ciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDV9CiMjIFBsb3QKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDUsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4xLjUiKSArIGNvb3JkX2ZpeGVkKCkgCmBgYAoKTWFrZSBpbmRpdmlkdWFsIHBsb3RzIGhpZ2hsaWdodGluZyB3aGVyZSBjZWxscyBpbiBlYWNoIGNsdXN0ZXIgZmFsbApgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyBmb3IgbG9vcCB3aGljaCB0YWtlcyBlYWNoIGNsdXN0ZXIgYW5kIG1ha2VzIGEgbGlzdCBvZiBjZWxscyBhbmQgdGhlbiBwbG90cyBhIGhpZ2hsaWdodGVkIHBsb3QgYW5kIGFkZHMgaXQgdG8gYSBsaXN0CgojIyBtYWtlIGEgYmxhbmsgbGlzdApsaXN0X1VNQVBzX2J5X2NsdXN0ZXIgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEuNSkpKQoKIyMgZm9yIGxvb3AKZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS41KSkpewogICMjIG1ha2UgYSBsaXN0IG9mIGNlbGxzCiAgbGlzdF9vZl9jZWxscyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS41ID09IGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS41KVtpXSksIF0pCiAgdWFtcF9wbG90IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBsaXN0X29mX2NlbGxzLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArCiAgICAjIyBmaXggY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiY2x1c3RlciIsIGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS41KVtpXSkpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIyBhZGQgdG8gdGhlIGxpc3QKICBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbW2ldXSA8LSB1YW1wX3Bsb3QKfQoKIyMgY2hlY2sgbnVtYmVyIG9mIGNsdXN0ZXJzCmxlbmd0aChsaXN0X1VNQVBzX2J5X2NsdXN0ZXIpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMjIDEuNSByZXNvbHV0aW9uCmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSAjKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI1XV0KYGBgCgojIyMjIHJlc29sdXRpb24gPSAyCgpWaWV3CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNX0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjIiKSArIGNvb3JkX2ZpeGVkKCkgCmBgYAoKTWFrZSBpbmRpdmlkdWFsIHBsb3RzIGhpZ2hsaWdodGluZyB3aGVyZSBjZWxscyBpbiBlYWNoIGNsdXN0ZXIgZmFsbApgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyBmb3IgbG9vcCB3aGljaCB0YWtlcyBlYWNoIGNsdXN0ZXIgYW5kIG1ha2VzIGEgbGlzdCBvZiBjZWxscyBhbmQgdGhlbiBwbG90cyBhIGhpZ2hsaWdodGVkIHBsb3QgYW5kIGFkZHMgaXQgdG8gYSBsaXN0CgojIyBtYWtlIGEgYmxhbmsgbGlzdApsaXN0X1VNQVBzX2J5X2NsdXN0ZXIgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjIpKSkKCiMjIGZvciBsb29wCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjIpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4yID09IGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMilbaV0pLCBdKQogIHVhbXBfcGxvdCA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gbGlzdF9vZl9jZWxscywgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKwogICAgIyMgZml4IGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImNsdXN0ZXIiLCBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjIpW2ldKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVhbXBfcGxvdAp9CgojIyBjaGVjayBudW1iZXIgb2YgY2x1c3RlcnMKbGVuZ3RoKGxpc3RfVU1BUHNfYnlfY2x1c3RlcikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIyB0aGlzIGZ1bmN0aW9uIHdyaXRlcyB0aGUgbmV4dCBiaXQgb2YgY29kZSBmb3IgeW91CiMjIHB1dCBpdCBpbnRvIHRoZSBjb25zb2xlIGFuZCBwYXN0ZSB0aGUgcmVzcG9uc2UKI3Bsb3R5IDwtIGMoKQojZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiMgIHBsb3R5IDwtIHBhc3RlMChwbG90eSwgImxpc3RfVU1BUHNfYnlfY2x1c3RlcltbIiwgaSwgIl1dIiwgIiArICIpCiN9CgojIyBwbG90Cmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjldXSMgKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzMwXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzMxXV0KYGBgCgo4IHZzIDExIG9uIHJlc29sdXRpb24gMiBhbHJlYWR5IGxvb2tzIHByZXR0eSBjb29sOgoKYGBge3J9CiMjIHJlc2V0IHRoZSBkZWZhdWx0IGlkZW50aXR5CiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBtaWQgcmVzb2x1dGlvbgojIyAyCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxNSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDIsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgoKIyMgRmluZCBkZWZlcmVudGlhbGx5IGV4cHJlc3NlZCBmZWF0dXJlcyBiZXR3ZWVuIHRoZSB0d28gY2x1c3RlcnMKZWFybHkuc2V4LmRlLm1hcmtlcnMgPC0gRmluZE1hcmtlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgaWRlbnQuMSA9ICI4IiwgaWRlbnQuMiA9ICIxMSIpCiMjIG9yZGVyIGJ5IEZDCmVhcmx5LnNleC5kZS5tYXJrZXJzIDwtIGVhcmx5LnNleC5kZS5tYXJrZXJzW3JldihvcmRlcihlYXJseS5zZXguZGUubWFya2VycyRhdmdfbG9nRkMpKSxdCiMjIHZpZXcgcmVzdWx0cwpoZWFkKGVhcmx5LnNleC5kZS5tYXJrZXJzKQojIFZpZXcoZWFybHkuc2V4LmRlLm1hcmtlcnMpCmBgYAoKYGBge3J9CmVhcmx5LnNleC5kZS5tYXJrZXJzLnNjcmVlbi5oaXRzIDwtIGVhcmx5LnNleC5kZS5tYXJrZXJzW3Jvd25hbWVzKGVhcmx5LnNleC5kZS5tYXJrZXJzKSAlaW4lIGMoc2NyZWVuX2hpdHMsIlBCQU5LQS0xNDM3NTAwIiksIF0KZWFybHkuc2V4LmRlLm1hcmtlcnMuc2NyZWVuLmhpdHMKCiMjIFBCQU5LQS0xMzAyNzAwIC0gbWQxCiMjIFBCQU5LQS0xNDM3NTAwIC0gQXAyRwojIyBQQkFOS0EtMTIxNDcwMCAtIGNvbnNlcnZlZCBwbGFzbW9kaXVtIHByb3RlaW4KYGBgCgpsb29rIGF0IHRoZW0gYWNyb3NzIHRoZSBkYXRhc2V0CgpgYGB7ciwgZmlnLmhlaWdodCA9IDZ9CkRvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSByb3duYW1lcyhlYXJseS5zZXguZGUubWFya2Vyc1sxOjEwLF0pKSArIFJvdGF0ZWRBeGlzKCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDZ9CkRvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBzY3JlZW5faGl0cykgKyBSb3RhdGVkQXhpcygpCmBgYAoKYGBge3J9CiMjIGZpbmQgYWxsIG1hcmtlcnMKI2FsbC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQsIG9ubHkucG9zID0gRkFMU0UsIG1pbi5wY3QgPSAwLjI1LCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQpgYGAKCmBgYHtyfQojdG9wX3R3byA8LSBhbGwubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPSAyLCB3dCA9IGF2Z19sb2dGQykKdG9wX3R3bwpgYGAKCgojIyMjIHJlc29sdXRpb24gPSA0CgpWaWV3CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNX0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjQiKSArIGNvb3JkX2ZpeGVkKCkgCmBgYAoKTWFrZSBpbmRpdmlkdWFsIHBsb3RzIGhpZ2hsaWdodGluZyB3aGVyZSBjZWxscyBpbiBlYWNoIGNsdXN0ZXIgZmFsbApgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyBmb3IgbG9vcCB3aGljaCB0YWtlcyBlYWNoIGNsdXN0ZXIgYW5kIG1ha2VzIGEgbGlzdCBvZiBjZWxscyBhbmQgdGhlbiBwbG90cyBhIGhpZ2hsaWdodGVkIHBsb3QgYW5kIGFkZHMgaXQgdG8gYSBsaXN0CgojIyBtYWtlIGEgYmxhbmsgbGlzdApsaXN0X1VNQVBzX2J5X2NsdXN0ZXIgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjQpKSkKCiMjIGZvciBsb29wCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjQpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy40ID09IGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuNClbaV0pLCBdKQogIHVhbXBfcGxvdCA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gbGlzdF9vZl9jZWxscywgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKwogICAgIyMgZml4IGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImNsdXN0ZXIiLCBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjQpW2ldKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVhbXBfcGxvdAp9CgojIyBjaGVjayBudW1iZXIgb2YgY2x1c3RlcnMKbGVuZ3RoKGxpc3RfVU1BUHNfYnlfY2x1c3RlcikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIyB0aGlzIGZ1bmN0aW9uIHdyaXRlcyB0aGUgbmV4dCBiaXQgb2YgY29kZSBmb3IgeW91CiMjIHB1dCBpdCBpbnRvIHRoZSBjb25zb2xlIGFuZCBwYXN0ZSB0aGUgcmVzcG9uc2UKI3Bsb3R5IDwtIGMoKQojZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiMgIHBsb3R5IDwtIHBhc3RlMChwbG90eSwgImxpc3RfVU1BUHNfYnlfY2x1c3RlcltbIiwgaSwgIl1dIiwgIiArICIpCiN9CgojIyBwbG90Cmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDZdXQpgYGAKCiMjIyMgVU1BUCBjbHVzdGVyaW5nCgpgYGB7cn0KIyMgcnVuIGEgbmV3IFVNQVAgd2l0aCAKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5jb21wb25lbnRzID0gMTApCmBgYAoKYGBge3J9CiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBsb3cgcmVzb2x1dGlvbgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IDE6MTAsIHJlZHVjdGlvbiA9ICJ1bWFwIikKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDAuNSwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKYGBgCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIGZvciBsb29wIHdoaWNoIHRha2VzIGVhY2ggY2x1c3RlciBhbmQgbWFrZXMgYSBsaXN0IG9mIGNlbGxzIGFuZCB0aGVuIHBsb3RzIGEgaGlnaGxpZ2h0ZWQgcGxvdCBhbmQgYWRkcyBpdCB0byBhIGxpc3QKCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMC41KSkpCgojIyBmb3IgbG9vcApmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4wLjUpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4wLjUgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4wLjUpW2ldKSwgXSkKICB1YW1wX3Bsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGxpc3Rfb2ZfY2VsbHMsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsKICAgICMjIGZpeCBjb29yZGluYXRlcwogICAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJjbHVzdGVyIiwgbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4wLjUpW2ldKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVhbXBfcGxvdAp9CgojIyBjaGVjayBudW1iZXIgb2YgY2x1c3RlcnMKbGVuZ3RoKGxpc3RfVU1BUHNfYnlfY2x1c3RlcikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIyB0aGlzIGZ1bmN0aW9uIHdyaXRlcyB0aGUgbmV4dCBiaXQgb2YgY29kZSBmb3IgeW91CiMjIHB1dCBpdCBpbnRvIHRoZSBjb25zb2xlIGFuZCBwYXN0ZSB0aGUgcmVzcG9uc2UKI3Bsb3R5IDwtIGMoKQojZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiMgIHBsb3R5IDwtIHBhc3RlMChwbG90eSwgImxpc3RfVU1BUHNfYnlfY2x1c3RlcltbIiwgaSwgIl1dIiwgIiArICIpCiN9CgojIyBwbG90Cmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXQpgYGAKCiMjIyBQaWNrIGZpbmFsIHJlc29sdXRpb24gCgpXZSB3aWxsIGxvb2sgaW4gbW9yZSBkZXRhaWwgYXQgY2VsbHMgYXMgdGhleSBlbnRlciB0aGUgc2V4dWFsIHRyYWplY290cnkgbGF0ZXIuIFRoZSBQQ0EgY2x1c3RlcmluZyB3aWxsIGJlIG1vcmUgYXBwcm9wcmlhdGUgaW4gdGhpcyBoaWdoLXJlc29sdXRpb24gdmlldy4gSW4gb3JkZXIgdG8gc3Vic2V0IHRoZXNlIGNlbGxzLCB3ZSB3aWxsIHVzZSB0aGUgVU1BUCBjbHVzdGVyaW5nLiAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNX0KIyMgZ2VuZXJhdGUgZmluYWwgY2x1c3RlcnMgd2hpY2ggd2lsbCBiZSB3cml0dGVuIGludG8gdGhlICdzZXVyYXQuY2x1c3RlcnMnIHNsb3QgaW4gbWV0YSBkYXRhCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxMCwgcmVkdWN0aW9uID0gInVtYXAiKQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gMC41LCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQoKIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyBjb29yZF9maXhlZCgpCmBgYAoKIyMjIGNsdXN0ZXJzIG1ldHJpY3MKCldlIHdpbGwgZ2V0IHNvbWUgaGlnaCBsZXZlbCBpbnNpZ2h0IGludG8gdGhlc2UgY2x1c3RlcnMgbm93CgpgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KIyMgVE9ETyAtIG1vdmUgdGhpcyB0byBvbmNlIGNsdXN0ZXJzIGFyZSBpZGVudGlmaWVkCnYxIDwtIFZsblBsb3Qob2JqZWN0ID0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAibkZlYXR1cmVfUk5BIiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgcHQuc2l6ZSA9IDAuMDEpCgp2MiA8LSBWbG5QbG90KG9iamVjdCA9IHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIm5Db3VudF9STkEiLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBwdC5zaXplID0gMC4wMSkKCnYxICsgdjIKYGBgCgojIDYuIERlZmluZSBDbHVzdGVyIElkZW50aXRpZXMgey50YWJzZXR9IAoKV2UgaGF2ZSBkZWZpbmVkIGNsdXN0ZXJzLCBub3cgd2Ugd2lsbCBpZGVudGlmeSB3aGF0IHRoZSBjbHVzdGVycyBjb3JyZXNwb25kIHRvLiBXZSBjYW4gdXNlIGEgbnVtYmVyIG9mIGV4dGVybmFsIGRhdGFzZXRzIHRvIGRvIHRoaXM6Cgprbm93biBtYXJrZXIgZ2VuZXMgCgpidWxrIFJOQS1zZXEgZGF0YSBjb3JyZWxhdGlvbiAKCiMjIyBNYXJrZXIgZ2VuZSBleHByZXNzaW9uCgojIyMjIGV4cHJlc3Npb24gb2YgODIwIG1hcmtlcnMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KIyMgbWFrZSBwbG90cyAKcGxvdHMgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIpLCBibGVuZCA9IFRSVUUsIGNvbWJpbmUgPSBGQUxTRSwgY29vcmQuZml4ZWQgPSBUUlVFLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKQogICAgCgojIEdldCBqdXN0IHRoZSBjby1leHByZXNzaW9uIHBsb3QsIGJ1aWx0LWluIGxlZ2VuZCBpcyBtZWFuaW5nbGVzcyBmb3IgdGhpcyBwbG90CiNwbG90c1tbM11dICsgTm9MZWdlbmQoKSAgCgojIEdldCBqdXN0IHRoZSBrZXkKI3Bsb3RzW1s0XV0gCgojIFN0aXRjaCB0aGUgY28tZXhwcmVzc2lvbiBhbmQga2V5IHBsb3RzIHRvZ2V0aGVyCnBsb3RzW1szXV0gKyBOb0xlZ2VuZCgpICsgcGxvdHNbWzRdXS9wbG90X3NwYWNlcigpICsgcGxvdF9sYXlvdXQod2lkdGhzID0gYygyLDEpKQpgYGAKCiMjIyMgS25vd24gTWFya2VyIEdlbmVzIFBsb3RzCgptYXJrZXIgZ2VuZXMgcGxvdHMKYGBge3IsIGZpZy5oZWlnaHQgPSAxNSwgZmlnLndpZHRoID0gMTV9CiMjIGZpbmQgYSBnb29kIHJpbmcgbWFya2VyLCB0byBzZWUgaWYgdGhlcmUgaXMgYSBiZXR0ZXIgb25lIHRoYW4gdGhlIG9uZXMgcmVwb3J0ZWQKI21hcmtlcnNfcmluZyA8LSBGaW5kTWFya2Vycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBpZGVudC4xID0gYygiNCIsICI1IiwgIjE2IiwgIjExIiwgIjciLCAiMyIsICI5IiwgIjAiLCAiMjIiKSkKI2hlYWQobWFya2Vyc19yaW5nKQoKIyBQQkFOS0EtMTMxOTUwMCAtIENDUDIgLSBmZW1hbGUgLSB1c2VkIGluIDgyMCBsaW5lCiMgUEJBTktBLTA0MTYxMDAgLSBNRzEgLSBkeW5lbmluIGhlYXZ5IGNoYWluIC0gbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMTQzNzUwMCAtIEFQMkcgLSBjb21taXRtZW50CiMgUEJBTktBLTA4MzEwMDAgLSBNU1AxIC0gbGF0ZSBhc2V4dWFsCiMgUEJBTktBLTExMDIyMDAgLSBNU1A4IC0gZWFybHkgYXNleHVhbCAoZnJvbSBCb3pkZWNoIHBhcGVyKQojIFBCQU5LQS0wNzExOTAwIC0gSFNQNzAgLSBwcm9tb3RlciB1c2VkIGZvciBHRlAgYW5kIFJGUCBleHByZXNzaW9uIGluIHRoZSBtdXRhbnRzCiMgUEJBTktBLTE0MDA0MDAgLSBGQU1CIC0gcmluZyBtYXJrZXIgLSBkaXNjb3ZlcmVkIGJ5IGxvb2tpbmcgZm9yIG1hcmtlciBnZW5lcyBpbiBkYXRhCiMgUEJBTktBLTA3MjI2MDAgLSBGYW0tYjIgLSByaW5nIG1hcmtlciAtIGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzUxMTMwMzEvIAoKCm1hcmtlcl9nZW5lX3Bsb3RfQ0NQMiA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTMxOTUwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIHB0LnNpemUgPSAxLCBvcmRlciA9IFRSVUUpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJDQ1AyIChGZW1hbGUpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkKCm1hcmtlcl9nZW5lX3Bsb3RfTUcxIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIlBCQU5LQS0wNDE2MTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIk1HMSAoTWFsZSkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgKyAKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKQoKbWFya2VyX2dlbmVfcGxvdF9BUDJHIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIlBCQU5LQS0xNDM3NTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIkFQMkcgKENvbW1pdG1lbnQpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkKCm1hcmtlcl9nZW5lX3Bsb3RfTVNQMSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDgzMTAwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIHB0LnNpemUgPSAxLCBvcmRlciA9IFRSVUUpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNU1AxIChTY2hpem9udCkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgKyAKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKQoKbWFya2VyX2dlbmVfcGxvdF9NU1A4IDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIlBCQU5LQS0xMTAyMjAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIk1TUDggKEFzZXh1YWwpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkKCm1hcmtlcl9nZW5lX3Bsb3RfU0JQMSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTEwMTMwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIHB0LnNpemUgPSAxLCBvcmRlciA9IFRSVUUpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJTQlAxIChSaW5nKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpCgptYXJrZXJfZ2VuZV9wbG90X0ZBTUIgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiUEJBTktBLTA3MjI2MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBwdC5zaXplID0gMSwgb3JkZXIgPSBUUlVFKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiRmFtLWIyIChSaW5nKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpCgptYXJrZXJfZ2VuZV9wbG90X0hTUDcwIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIlBCQU5LQS0wNzExOTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIihIU1A3MDsgUmVwb3J0ZXIpIiwiXG4iLCAiUEJBTktBXzA3MTE5MDAiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgKyAKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKQoKIyNvcmlnaW5hbCBsYWJlbDoKIyBsYWJzKHRpdGxlID0gcGFzdGUoIihDQ1AyOyBGZW1hbGUpIiwiXG4iLCAiUEJBTktBXzEzMTk1MDAiKSkKCiMjIHBsb3QKIyMgY293cGxvdCBtZXRob2QKbWFya2VyX2dlbmVfcGxvdF9hbGwgPC0gcGxvdF9ncmlkKG1hcmtlcl9nZW5lX3Bsb3RfRkFNQiwgbWFya2VyX2dlbmVfcGxvdF9NU1A4LCBtYXJrZXJfZ2VuZV9wbG90X01TUDEsIG1hcmtlcl9nZW5lX3Bsb3RfQVAyRywgbWFya2VyX2dlbmVfcGxvdF9DQ1AyLCBtYXJrZXJfZ2VuZV9wbG90X01HMSwgbWFya2VyX2dlbmVfcGxvdF9IU1A3MCwgbnJvdz0zKQoKbWFya2VyX2dlbmVfcGxvdF9hbGwKCiMjIHBhdGNod29yayBtZXRob2QKI21hcmtlcl9nZW5lX3Bsb3RfRkFNQiArIG1hcmtlcl9nZW5lX3Bsb3RfTVNQOCArIG1hcmtlcl9nZW5lX3Bsb3RfTVNQMSArIG1hcmtlcl9nZW5lX3Bsb3RfQVAyRyArIG1hcmtlcl9nZW5lX3Bsb3RfQ0NQMiArIG1hcmtlcl9nZW5lX3Bsb3RfTUcxICsgbWFya2VyX2dlbmVfcGxvdF9IU1A3MApgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTUsIGZpZy53aWR0aCA9IDE1fQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMDQxNjEwMCAtIE1HMSAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0xNDM3NTAwIC0gQVAyRyAtIGNvbW1pdG1lbnQKIyBQQkFOS0EtMDgzMTAwMCAtIE1TUDEgLSBsYXRlIGFzZXh1YWwKIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpCiMgUEJBTktBLTA3MTE5MDAgLSBIU1A3MCAtIHByb21vdGVyIHVzZWQgZm9yIEdGUCBhbmQgUkZQIGV4cHJlc3Npb24gaW4gdGhlIG11dGFudHMKIyBQQkFOS0EtMTQwMDQwMCAtIEZBTUIgLSByaW5nIG1hcmtlciAtIGRpc2NvdmVyZWQgYnkgbG9va2luZyBmb3IgbWFya2VyIGdlbmVzIGluIGRhdGEKIyBQQkFOS0EtMDcyMjYwMCAtIEZhbS1iMiAtIHJpbmcgbWFya2VyIC0gaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNTExMzAzMS8gCm1hcmtlcnNfbGlzdCA8LSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDgzMTAwMCIsICJQQkFOS0EtMTEwMjIwMCIsICJQQkFOS0EtMDcxMTkwMCIsICJQQkFOS0EtMTQwMDQwMCIsICJQQkFOS0EtMDcyMjYwMCIpCgpsaXN0X29mX2RlbnNpdHlfcGxvdHMgPC0gcGxvdF9kZW5zaXR5KHRlbngubXV0YW50LmludGVncmF0ZWQsIG1hcmtlcnNfbGlzdCwgam9pbnQgPSBGQUxTRSwgY29tYmluZSA9IEZBTFNFLCBkaW1zID0gYygyLDEpLCBwYWwgPSAicGxhc21hIikKCmxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbMV1dICsgY29vcmRfZml4ZWQoKSArIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbMl1dICsgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1szXV0gKyBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzRdXSArIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbNV1dICsgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1s2XV0gKyBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzddXSArIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbOF1dCgojcGxvdF9kZW5zaXR5KHRlbngubXV0YW50LmludGVncmF0ZWQsICJQQkFOS0EtMDQxNjEwMCIpCmBgYAoKTXV0YW50IGNlbGxzIGNvdWxkIGhhdmUgYWJlcmFudCBleHByZXNzaW9uIHNvIHdlIHdpbGwgdXNlIG9ubHkgd2lsZC10eXBlIGNlbGxzOgoKbWFrZSBhIG1ldGFkYXRhIGNvbHVtbiB3aGVyZSB0aGUgMTBYIGRhdGEgaXMgY2xhc3NpZmllZCBhcyBhIFdUIGdlbm90eXBlCmBgYHtyfQojIyBnZXQgY2VsbHMgdGhhdCBhcmUgZmlsdGVyZWQgb3V0CmNlbGxzXzEweCA8LSB3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRleHBlcmltZW50ID09ICJ0ZW54XzVrIikKCiMjIG1ha2UgZXh0cmEgY29sdW1uIGluIHBsb3R0aW5nIGRmCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGdlbm90eXBlX2NvbWJpbmVkIDwtIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGdlbm90eXBlCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGdlbm90eXBlX2NvbWJpbmVkW2NlbGxzXzEweF0gPC0gIldUIgoKIyMgaW5zcGVjdAp0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRnZW5vdHlwZV9jb21iaW5lZCkKYGBgCgoKYGBge3J9CndpbGRfdHlwZV9jZWxscyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRnZW5vdHlwZV9jb21iaW5lZCA9PSAiV1QiLCBdKQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnd0IDwtIHN1YnNldCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBjZWxscyA9IHdpbGRfdHlwZV9jZWxscykKI0ZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQud3QsIGZlYXR1cmVzID0gIlBCQU5LQS0xMTAxMzAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkKCiMjIFJ1biB0aGUgc3RhbmRhcmQgd29ya2Zsb3cgZm9yIHZpc3VhbGl6YXRpb24gYW5kIGNsdXN0ZXJpbmcKI3RlbngubXV0YW50LmludGVncmF0ZWQud3QgPC0gU2NhbGVEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQud3QsIHZlcmJvc2UgPSBGQUxTRSkKI3RlbngubXV0YW50LmludGVncmF0ZWQud3QgPC0gUnVuUENBKHRlbngubXV0YW50LmludGVncmF0ZWQud3QsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQoKIyMgaW5zcGVjdCBQQ3MKI0VsYm93UGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnd0LCBuZGltcyA9IDMwLCByZWR1Y3Rpb24gPSAicGNhIikKCiMjIFJ1biBvcHRpbWlzZWQgVU1BUAojdGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dCA8LSBSdW5VTUFQKHRlbngubXV0YW50LmludGVncmF0ZWQud3QsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjQsIHJlcHVsc2lvbi5zdHJlbmd0aCA9IDAuMDMsIGxvY2FsLmNvbm5lY3Rpdml0eSA9IDE1MCkKCiMjIHBsb3QKI2RwMSA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQud3QsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBGQUxTRSwgcHQuc2l6ZSA9IDAuMDUsIGRpbXMgPSBjKDIsMSksIGdyb3VwLmJ5ID0gImV4cGVyaW1lbnQiKSArIAogICMjIGZpeCB0aGUgYXhpcwogICNjb29yZF9maXhlZCgpICsgCiAgIyMgcmV2ZXJzZSB0aGUgc2NhbGUKICAjc2NhbGVfeV9yZXZlcnNlKCkKCiMjIHZpZXcKI2RwMQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTUsIGZpZy53aWR0aCA9IDE1fQpwbG90X2RlbnNpdHkodGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dCwgbWFya2Vyc19saXN0LCBqb2ludCA9IEZBTFNFLCBkaW1zID0gYygyLDEpLCBwYWwgPSAicGxhc21hIikKYGBgCgoKVGhlbiBkZWZpbmUgZWFjaCBjbHVzdGVyIGFzIE1hbGUsIEZlbWFsZSBvciBBc2V4dWFsOgpgYGB7cn0KIyMgY29weSBjbHVzdGVycyB0byBuZXcgY29sdW1uCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPC0gTkEKCiMjIGRlZmluZSB3aGljaCBjbHVzdGVycyB3aWxsIGJlIHdoaWNoIGlkZW50aXR5CgptYWxlX2NsdXN0ZXJzIDwtIGMoIjIyIiwgIjE4IiwgIjkiLCAiMTYiKQoKZmVtYWxlX2NsdXN0ZXJzIDwtIGMoIjE5IiwiMjQiLCIyMCIsIjMiKQoKYXNleF9jbHVzdGVycyA8LSBjKCI4IiwiMSIsIjAiLCI0IiwiMiIsIjYiLCI3IiwiNSIsIjEyIiwiMTQiLCIxNSIsIjEwIiwiMjMiLCIxMyIsIjE3IiwiMjEiLCIyNSIpCgpiaXBvdGVudGlhbF9jbHVzdGVycyA8LSBjKCIxMSIpCgojIyBjaGVjayBsZW5ndGggb2YgdGhlIHVuaXF1ZSBlbnRyaWVzIGluIHRoZSBtYW51YWx5IGNyZWF0ZWQgbGlzdCBhYm92ZSBhbmQgdGhlIG51bWJlciBvZiBjbHVzdGVycyBpbiB0b3RhbApwYXN0ZSgiSXMgdGhlIHRvdGFsIG51bWJlciBvZiBjbHVzdGVycyBpbiB0aGUgbGlzdCB0aGUgc2FtZSBhcyB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIGluIHRoZSBzbG90PyIsIGlkZW50aWNhbChsZW5ndGgodW5pcXVlKGMobWFsZV9jbHVzdGVycywgZmVtYWxlX2NsdXN0ZXJzLCBhc2V4X2NsdXN0ZXJzLCBiaXBvdGVudGlhbF9jbHVzdGVycykpKSwgbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSkpCgojIyBjaGFuZ2UgdGhlIGNvbHVtbiBJRHMKdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2x1c3Rlcl9jb2xvdXJzX2ZpZ3VyZVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgJWluJSBtYWxlX2NsdXN0ZXJzKV0gPC0gIk1hbGUiCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmVbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzICVpbiUgZmVtYWxlX2NsdXN0ZXJzKV0gPC0gIkZlbWFsZSIKdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2x1c3Rlcl9jb2xvdXJzX2ZpZ3VyZVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgJWluJSBhc2V4X2NsdXN0ZXJzKV0gPC0gIkFzZXh1YWwiCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmVbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYmlwb3RlbnRpYWxfY2x1c3RlcnMpXSA8LSAiQmlwb3RlbnRpYWwiCgp0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRjbHVzdGVyX2NvbG91cnNfZmlndXJlKQpgYGAKCiMgNy4gUGxvdCBGaWd1cmVzIHsudGFic2V0fQoKdXNlZnVsIHRvb2xzIGZvciBhbGwgcGxvdHMKYGBge3J9CiMjIGRlZmluZSBtYWxlIGFuZCBmZW1hbGUgc3ltYm9sCmZlbWFsZV9zeW1ib2wgPC0gaW50VG9VdGY4KDk3OTIpCm1hbGVfc3ltYm9sIDwtIGludFRvVXRmOCg5Nzk0KQpgYGAKCgojIyMjIEZpZy4gMy5BLiAoQWxsIENlbGxzIGJ5IE1hbGUsIEZlbWFsZSwgTWFsZSkKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNH0KIyMgbWFrZSBhIGN1c3RvbSBwYWwKIyAxID0gYmx1ZSAtICIjMDA1MmM1IgojIDIgPSByZWQgLSAiI2E1MmIxZSIKIyAzID0gZ3JlZW4gLSAiIzAxNmMwMCIKIyA0ID0geWVsbG93IC0gIiNmZmU0MDAiCnBhbF9zZXggPC0gYygiIzAwNTJjNSIsIiNmZmU0MDAiLCAiI2E1MmIxZSIsICIjMDE2YzAwIikKClVNQVBfaWRlbnRpdHkgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gImNsdXN0ZXJfY29sb3Vyc19maWd1cmUiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPXBhbF9zZXgpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKIyMgcHJpbnQKVU1BUF9pZGVudGl0eQpgYGAKCnNhdmUKYGBge3J9Cmdnc2F2ZSgiLi4vaW1hZ2VzX3RvX2V4cG9ydC9tZXJnZV9VTUFQX2lkZW50aXR5LnBuZyIsIHBsb3QgPSBVTUFQX2lkZW50aXR5LCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMjAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyMgRmlnLiBTdXAuIFVNQVAgd2l0aCBDbHVzdGVycwoKYGBge3IsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA3fQojIyBQbG90CnVtYXBfY2x1c3RlciA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDgsIHJlcGVsID0gRkFMU0UsIHB0LnNpemUgPSAwLjUsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCAKICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpKSArIAogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3cgPSAzLCBieXJvdyA9IFRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0xMCkpKQoKIyMgcHJpbnQKdW1hcF9jbHVzdGVyCmBgYAoKc2F2ZQpgYGB7cn0KZ2dzYXZlKCIuLi9pbWFnZXNfdG9fZXhwb3J0L21lcmdlX1VNQVBfY2x1c3Rlci5wbmciLCBwbG90ID0gdW1hcF9jbHVzdGVyLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMjAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyMgRmlnLiAzLkMuIEJ5IGJ1bGsgY29ycmVsYXRpb24KCmBgYHtyfQojIyBtYWtlIHBsb3RzCiMjIGhvbyBkYXRhc2V0IGNvcnJlbGF0aW9uClVNQVBfaG9vIDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uLlNwZWFybWFuLiIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsKICBjb29yZF9maXhlZCgpICsgCiAgdGhlbWVfdm9pZCgpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIkhvbyBQcmVkaWN0ZWQgVGltZXBvaW50IikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGluZmVybm8oMTIpKSAgKwogIGxhYnMoY29sb3VyID0gImhvdXIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCkpCgojIyBhcDJnIHRpbWVjb3Vyc2UgaW4gdGhpcyBwYXBlciBjb3JyZWxhdGlvbgpVTUFQX2thc2lhIDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uLlNwZWFybWFuLl9LYXNpYSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsKICBjb29yZF9maXhlZCgpICsgCiAgdGhlbWVfdm9pZCgpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIkFQMkcgVGltZWNvdXJzZSBQcmVkaWN0ZWQgVGltZXBvaW50IikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGluZmVybm8oMTApKSAgKwogIGxhYnMoY29sb3VyID0gImhvdXIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCkpCgojIyBjb21iaW5lCnVtYXBfYnVsayA8LSB3cmFwX3Bsb3RzKFVNQVBfaG9vLCBVTUFQX2thc2lhLCBuY29sID0gMikKCiMjIHByaW50CnVtYXBfYnVsawpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2ltYWdlc190b19leHBvcnQvbWVyZ2VfdW1hcF9idWxrX3ByZWRpY3Rpb24ucG5nIiwgcGxvdCA9IHVtYXBfYnVsaywgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMzAsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgojIyMjIEZpZy4gMy5DLiBCeSBFeHBlcmltZW50CgpUaGUgb3JpZ2luYWwgbWV0aG9kIG9mIHBsb3R0aW5nIGJ5IGV4cGVyaW1lbnQgZG9lcyBub3QgYWxsb3cgbXVjaCBjdXN0b21pc2F0aW9uIG9mIHRoZSBwbG90cy4gSS5lLiB3ZSBjYW5ub3QgZWFzaWx5IGNoYW5nZSB0aGUgdGl0bGVzIG9mIGVhY2ggcGxvdApgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CiMjIFBsb3QKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuNSwgc3BsaXQuYnkgPSAiZXhwZXJpbWVudCIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSxheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpKQpgYGAKCkJ1dCwgd2UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIGNvZGUgdG8gZG8gdGhpcwpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDh9CiMjIG1ha2UgYW4gZXh0cmEgbWV0YS5kYXRhIGNvbHVtbiBzbyB5b3UgY2FuIHNwbGl0IHRoZSBvYmplY3QgYnkgU1MyIG11dGFudCwgU1MyIFdULCAxMFgKIyMgbWFrZSBuZXcgY29sdW1uIGluIG1ldGEuZGF0YQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzdWJfZ2Vub3R5cGUgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkZ2Vub3R5cGUKCiMjIHJlcGxhY2UgTkEgdmFsdWVzIGZyb20gMTBYIGRhdGEgd2l0aCBhIHZhbHVlCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHN1Yl9nZW5vdHlwZVtpcy5uYSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzdWJfZ2Vub3R5cGUpXSA8LSAiMTBYX1dUIgoKIyMgY2hlY2sKdGFibGUodGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc3ViX2dlbm90eXBlKQoKIyMgc3BsaXQgc2V1cmF0IG9iamVjdCB1cApvYi5saXN0IDwtIFNwbGl0T2JqZWN0KHRlbngubXV0YW50LmludGVncmF0ZWQsIHNwbGl0LmJ5ID0gInN1Yl9nZW5vdHlwZSIpCgojIyBtYWtlIHBsb3RzIGZvciBlYWNoIG9iamVjdApwbG90Lmxpc3QgPC0gbGFwcGx5KFggPSBvYi5saXN0LCBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICBEaW1QbG90KHgsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGxhYmVsID0gRkFMU0UsIGxhYmVsLnNpemUgPSA1LCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAxKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikKfSkKCiMjIHVzZSB0aGlzIGZ1bmN0aW9uIHRvIGV4dHJhY3QgbGVnZW5kOgojIyBzb3VyY2U6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEzNjQ5NDczL2FkZC1hLWNvbW1vbi1sZWdlbmQtZm9yLWNvbWJpbmVkLWdncGxvdHMKIyMgc291cmNlOiBodHRwczovL2dpdGh1Yi5jb20vaGFkbGV5L2dncGxvdDIvd2lraS9TaGFyZS1hLWxlZ2VuZC1iZXR3ZWVuLXR3by1nZ3Bsb3QyLWdyYXBocwpnX2xlZ2VuZDwtZnVuY3Rpb24oYS5ncGxvdCl7CiAgIHRtcCA8LSBnZ3Bsb3RfZ3RhYmxlKGdncGxvdF9idWlsZChhLmdwbG90KSkKICAgbGVnIDwtIHdoaWNoKHNhcHBseSh0bXAkZ3JvYnMsIGZ1bmN0aW9uKHgpIHgkbmFtZSkgPT0gImd1aWRlLWJveCIpCiAgIGxlZ2VuZCA8LSB0bXAkZ3JvYnNbW2xlZ11dCiAgIHJldHVybihsZWdlbmQpfQoKIyMgbWFrZSBwbG90cyBwcmV0dHkKcDEgPC0gcGxvdC5saXN0JGAxMFhfV1RgICsgdGhlbWVfdm9pZCgpICsgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCnAyIDwtIHBsb3QubGlzdCRXVCArIHRoZW1lX3ZvaWQoKQpwMyA8LSBwbG90Lmxpc3QkTXV0YW50ICsgdGhlbWVfdm9pZCgpCgojIyBnZXQgbGVnZW5kCm15bGVnZW5kPC1nX2xlZ2VuZChwMSkKCiMjIG1ha2UgYSBmaW5hbCBwbG90CnA0IDwtIGdyaWQuYXJyYW5nZShhcnJhbmdlR3JvYihwMSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgbGFicyh0aXRsZSA9IHBhc3RlKCIxMFgiLCAiXG4iLCAiKHdpbGQtdHlwZSkiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMiArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJTbWFydC1zZXEyIiwgIlxuIiwgIih3aWxkLXR5cGUpIikpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDMgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiU21hcnQtc2VxMiIsICJcbiIsICIobXV0YW50KSIpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSwgbnJvdz0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15bGVnZW5kLCBucm93PTIsaGVpZ2h0cz1jKDEwLCAxKSkKYGBgCgpNYWtlIGZpbmFsIHBsb3RzOgpgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KcDEgPC0gcGxvdC5saXN0JGAxMFhfV1RgICsgCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMocmVwbGljYXRlKDQ1LCAiIzk5OTk5OSIpKSkgKwogIGxhYnModGl0bGUgPSBwYXN0ZSgiMTBYICh3aWxkLXR5cGUpIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKcDIgPC0gcGxvdC5saXN0JFdUICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhyZXBsaWNhdGUoNDYsICIjOTk5OTk5IikpKSArCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJTbWFydC1zZXEyICh3aWxkLXR5cGUpIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKcDMgPC0gcGxvdC5saXN0JE11dGFudCArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMocmVwbGljYXRlKDQ2LCAiIzk5OTk5OSIpKSkgKwogIGxhYnModGl0bGUgPSBwYXN0ZSgiU21hcnQtc2VxMiAobXV0YW50KSIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCnAxICsgcDIgKyBwMwpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIyBtYWtlIGNvbXBvc2l0ZSBwbG90ClVNQVBfY29tcG9zaXRlIDwtIHdyYXBfcGxvdHMobWFya2VyX2dlbmVfcGxvdF9GQU1CICwgbWFya2VyX2dlbmVfcGxvdF9NU1A4ICwgbWFya2VyX2dlbmVfcGxvdF9NU1AxICwgbWFya2VyX2dlbmVfcGxvdF9BUDJHICwgbWFya2VyX2dlbmVfcGxvdF9DQ1AyICwgbWFya2VyX2dlbmVfcGxvdF9NRzEgLCBwMSAsIHAyICwgcDMsIG5jb2wgPSAzKQoKIyMgcHJpbnQKVU1BUF9jb21wb3NpdGUKYGBgCnNhdmUKYGBge3J9Cmdnc2F2ZSgiLi4vaW1hZ2VzX3RvX2V4cG9ydC9tZXJnZV91bWFwX3RlY2hub2xvZ3lfYW5kX21hcmtlcnMucG5nIiwgcGxvdCA9IFVNQVBfY29tcG9zaXRlLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAzMCwgaGVpZ2h0ID0gMzAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMDQxNjEwMCAtIE1HMSAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0xNDM3NTAwIC0gQVAyRyAtIGNvbW1pdG1lbnQKIyBQQkFOS0EtMDgzMTAwMCAtIE1TUDEgLSBsYXRlIGFzZXh1YWwKIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpCiMgUEJBTktBLTA3MTE5MDAgLSBIU1A3MCAtIHByb21vdGVyIHVzZWQgZm9yIEdGUCBhbmQgUkZQIGV4cHJlc3Npb24gaW4gdGhlIG11dGFudHMKIyBQQkFOS0EtMTQwMDQwMCAtIEZBTUIgLSByaW5nIG1hcmtlciAtIGRpc2NvdmVyZWQgYnkgbG9va2luZyBmb3IgbWFya2VyIGdlbmVzIGluIGRhdGEKIyBQQkFOS0EtMDcyMjYwMCAtIEZhbS1iMiAtIHJpbmcgbWFya2VyIC0gaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNTExMzAzMS8gCgojICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgKyAKCm1hcmtlcnNfbGlzdCA8LSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDgzMTAwMCIsICJQQkFOS0EtMTEwMjIwMCIsICJQQkFOS0EtMDcxMTkwMCIsICJQQkFOS0EtMTQwMDQwMCIsICJQQkFOS0EtMDcyMjYwMCIpCgpsaXN0X29mX2RlbnNpdHlfcGxvdHMgPC0gcGxvdF9kZW5zaXR5KHRlbngubXV0YW50LmludGVncmF0ZWQud3QsIG1hcmtlcnNfbGlzdCwgam9pbnQgPSBGQUxTRSwgY29tYmluZSA9IEZBTFNFLCBkaW1zID0gYygyLDEpLCBwYWwgPSAicGxhc21hIiwgbWV0aG9kID0gImtzIikKCiMjIG1ha2UgY29tcG9zaXRlIHBsb3QKVU1BUF9jb21wb3NpdGUgPC0gd3JhcF9wbG90cyhsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzhdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIkZhbS1iMiAoUmluZykiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzVdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk1TUDggKEFzZXh1YWwpIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1s0XV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJNU1AxIChTY2hpem9udCkiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzNdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIkFQMkcgKENvbW1pdG1lbnQpIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSApKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1sxXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJDQ1AyIChGZW1hbGUpIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1syXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJNRzEgKE1hbGUpIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDEgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMiAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMykKClVNQVBfY29tcG9zaXRlCmBgYAoKU3BlY2lmaWMgZ2VuZSBleHByZXNzaW9uIG9mIG11dGFudHMKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMgUEJBTktBLTE0MTgxMDAgICAgICAgIEdDU0tPLTE3ICBGRDMgICAKIyBQQkFOS0EtMDEwMjQwMCAgICAgICAgIEdDU0tPLTIgIE1EMyAKIyBQQkFOS0EtMDcxNjUwMCAgICAgICAgR0NTS08tMTkgIE1ENCAKIyBQQkFOS0EtMTQzNTIwMCAgICAgICAgR0NTS08tMjAgIEZENCAKIyBQQkFOS0EtMDkwMjMwMCAgICAgICAgR0NTS08tMTMgIEZEMgojIFBCQU5LQS0wNDEzNDAwICAgIEdDU0tPLTEwXzgyMCAgTUQ1CiMgUEJBTktBLTA4MjgwMDAgICAgICAgICBHQ1NLTy0zICBHRDEKIyBQQkFOS0EtMTMwMjcwMCAgICAgICBHQ1NLTy1vb20gIE1EMSAKIyBQQkFOS0EtMTQ0NzkwMCAgICAgICAgR0NTS08tMjkgIE1EMgojIFBCQU5LQS0xNDU0ODAwICAgICAgICBHQ1NLTy0yMSAgRkQxCiMgUEJBTktBLTExNDQ4MDAgICAgICAgIEdDU0tPLTI4ICBGRDUKCgptYXJrZXJfZ2VuZV9wbG90XzE3IDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0xNDE4MTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExMCIsIG1heC5jdXRvZmYgPSAicTk1IiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImZkMyIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgptYXJrZXJfZ2VuZV9wbG90XzIgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZmVhdHVyZXMgPSAiUEJBTktBLTAxMDI0MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEwIiwgbWF4LmN1dG9mZiA9ICJxOTUiLCBwdC5zaXplID0gMSwgb3JkZXIgPSBUUlVFKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiMiIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgptYXJrZXJfZ2VuZV9wbG90XzE5IDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0wNzE2NTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExMCIsIG1heC5jdXRvZmYgPSAicTk1IiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIjE5IikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKwogICMjIGFkZCBzZXggc3ltYm9scwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDMuOCwgeSA9IDEuNSwgbGFiZWwgPSBtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMiwgeSA9IDIuOCwgbGFiZWwgPSBmZW1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikKCm1hcmtlcl9nZW5lX3Bsb3RfMjAgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZmVhdHVyZXMgPSAiUEJBTktBLTE0MzUyMDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEwIiwgbWF4LmN1dG9mZiA9ICJxOTUiLCBwdC5zaXplID0gMSwgb3JkZXIgPSBUUlVFKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiMjAiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgKyAKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArCiAgIyMgYWRkIHNleCBzeW1ib2xzCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy44LCB5ID0gMS41LCBsYWJlbCA9IG1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLCB5ID0gMi44LCBsYWJlbCA9IGZlbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKQoKbWFya2VyX2dlbmVfcGxvdF8xMyA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDkwMjMwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMTAiLCBtYXguY3V0b2ZmID0gInE5NSIsIHB0LnNpemUgPSAxLCBvcmRlciA9IFRSVUUpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIxMyIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgptYXJrZXJfZ2VuZV9wbG90XzEwIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0wNDEzNDAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExMCIsIG1heC5jdXRvZmYgPSAicTk1IiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIjEwIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKwogICMjIGFkZCBzZXggc3ltYm9scwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDMuOCwgeSA9IDEuNSwgbGFiZWwgPSBtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMiwgeSA9IDIuOCwgbGFiZWwgPSBmZW1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikKCm1hcmtlcl9nZW5lX3Bsb3RfMyA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDgyODAwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMTAiLCBtYXguY3V0b2ZmID0gInE5NSIsIHB0LnNpemUgPSAxLCBvcmRlciA9IFRSVUUpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIzIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKwogICMjIGFkZCBzZXggc3ltYm9scwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDMuOCwgeSA9IDEuNSwgbGFiZWwgPSBtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMiwgeSA9IDIuOCwgbGFiZWwgPSBmZW1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikKCm1hcmtlcl9nZW5lX3Bsb3Rfb29tIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0xMzAyNzAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExMCIsIG1heC5jdXRvZmYgPSAicTk1IiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIm9vbSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKSArIAogIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgptYXJrZXJfZ2VuZV9wbG90XzI5IDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0xNDQ3OTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExMCIsIG1heC5jdXRvZmYgPSAicTk1IiwgcHQuc2l6ZSA9IDEsIG9yZGVyID0gVFJVRSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIjI5IikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpICsgCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKwogICMjIGFkZCBzZXggc3ltYm9scwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDMuOCwgeSA9IDEuNSwgbGFiZWwgPSBtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMiwgeSA9IDIuOCwgbGFiZWwgPSBmZW1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikKCm1hcmtlcl9nZW5lX3Bsb3RfMjEgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZmVhdHVyZXMgPSAiUEJBTktBLTE0NTQ4MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEwIiwgbWF4LmN1dG9mZiA9ICJxOTUiLCBwdC5zaXplID0gMSwgb3JkZXIgPSBUUlVFKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiMjEiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgKyAKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArCiAgIyMgYWRkIHNleCBzeW1ib2xzCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy44LCB5ID0gMS41LCBsYWJlbCA9IG1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLCB5ID0gMi44LCBsYWJlbCA9IGZlbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKQoKIyNvcmlnaW5hbCBsYWJlbDoKIyBsYWJzKHRpdGxlID0gcGFzdGUoIihDQ1AyOyBGZW1hbGUpIiwiXG4iLCAiUEJBTktBXzEzMTk1MDAiKSkKCiMjIG1ha2UgY29tcG9zaXRlIHBsb3QKbXV0YW50X2V4cHJlc3Npb25fY29tcG9zaXRlIDwtIHdyYXBfcGxvdHMobWFya2VyX2dlbmVfcGxvdF8xNyAsIG1hcmtlcl9nZW5lX3Bsb3RfMiAsIG1hcmtlcl9nZW5lX3Bsb3RfMTkgLCBtYXJrZXJfZ2VuZV9wbG90XzIwICwgbWFya2VyX2dlbmVfcGxvdF8xMyAsIG1hcmtlcl9nZW5lX3Bsb3RfMTAgLCBtYXJrZXJfZ2VuZV9wbG90XzMgLCBtYXJrZXJfZ2VuZV9wbG90X29vbSAsIG1hcmtlcl9nZW5lX3Bsb3RfMjkgLCBtYXJrZXJfZ2VuZV9wbG90XzIxICwgbmNvbCA9IDQpCiAgICAgICAgICAgCiMjIHByaW50Cm11dGFudF9leHByZXNzaW9uX2NvbXBvc2l0ZQpgYGAKCnNhdmUKYGBge3J9Cmdnc2F2ZSgiLi4vaW1hZ2VzX3RvX2V4cG9ydC9tZXJnZV91bWFwX211dGFudF9nZW5lX2V4cHJlc3Npb24ucG5nIiwgcGxvdCA9IG11dGFudF9leHByZXNzaW9uX2NvbXBvc2l0ZSwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMzAsIGhlaWdodCA9IDMwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgpEZW5zaXR5IHBsb3QgdmVyc2lvbgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMgUEJBTktBLTA4MjgwMDAgICAgICAgICBHQ1NLTy0zICBHRDEKCiMgUEJBTktBLTEzMDI3MDAgICAgICAgR0NTS08tb29tICBNRDEgCiMgUEJBTktBLTE0NDc5MDAgICAgICAgIEdDU0tPLTI5ICBNRDIKIyBQQkFOS0EtMDEwMjQwMCAgICAgICAgIEdDU0tPLTIgIE1EMyAKIyBQQkFOS0EtMDcxNjUwMCAgICAgICAgR0NTS08tMTkgIE1ENCAKIyBQQkFOS0EtMDQxMzQwMCAgICBHQ1NLTy0xMF84MjAgIE1ENQoKIyBQQkFOS0EtMTQ1NDgwMCAgICAgICAgR0NTS08tMjEgIEZEMQojIFBCQU5LQS0wOTAyMzAwICAgICAgICBHQ1NLTy0xMyAgRkQyCiMgUEJBTktBLTE0MTgxMDAgICAgICAgIEdDU0tPLTE3ICBGRDMgICAKIyBQQkFOS0EtMTQzNTIwMCAgICAgICAgR0NTS08tMjAgIEZENCAKCm1hcmtlcnNfbGlzdCA8LSBjKCJQQkFOS0EtMDgyODAwMCIsICJQQkFOS0EtMTMwMjcwMCIsICJQQkFOS0EtMTQ0NzkwMCIsICJQQkFOS0EtMDEwMjQwMCIsICJQQkFOS0EtMDcxNjUwMCIsICJQQkFOS0EtMDQxMzQwMCIsICJQQkFOS0EtMTQ1NDgwMCIsICJQQkFOS0EtMDkwMjMwMCIsICJQQkFOS0EtMTQxODEwMCIsICJQQkFOS0EtMTQzNTIwMCIpCgpsaXN0X29mX2RlbnNpdHlfcGxvdHNfbXV0YW50X2dlbmVzIDwtIHBsb3RfZGVuc2l0eSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnd0LCBtYXJrZXJzX2xpc3QsIGpvaW50ID0gRkFMU0UsIGNvbWJpbmUgPSBGQUxTRSwgZGltcyA9IGMoMiwxKSwgcGFsID0gInBsYXNtYSIsIG1ldGhvZCA9ICJrcyIpCgojIyBtYWtlIGNvbXBvc2l0ZSBwbG90ClVNQVBfY29tcG9zaXRlX211dGFudF9nZW5lcyA8LSB3cmFwX3Bsb3RzKGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzFdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoImdkMSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzJdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIm1kMSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzNdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIm1kMiIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzRdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIm1kMyIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkgKSsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzVdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIm1kNCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzZdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIm1kNSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzddXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoImZkMSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzhdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoImZkMiIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzldXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlID0gcGFzdGUoImZkMyIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzEwXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJmZDQiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gNCkKClVNQVBfY29tcG9zaXRlX211dGFudF9nZW5lcwpgYGAKc2F2ZQpgYGB7cn0KZ2dzYXZlKCIuLi9pbWFnZXNfdG9fZXhwb3J0L21lcmdlX3VtYXBfbXV0YW50X2dlbmVfZXhwcmVzc2lvbi5wbmciLCBwbG90ID0gVU1BUF9jb21wb3NpdGVfbXV0YW50X2dlbmVzLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAzMCwgaGVpZ2h0ID0gMzAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyMgRmlnLiBTdXAuIExvb2sgYXQgc3BlY2lmaWMgbXV0YW50cwoKQWxsIHRoZSBtdXRhbnQgZ2Vub3R5cGVzIHByb2ZpbGVkIHdlcmU6CmBgYHtyfQojIyBtYWtlIGEgbGlzdCBvZiBwb3NzaWJsZSBnZW5vdHlwZXMKdW5pcXVlKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQpCnVuaXF1ZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV9uYW1lX3VwZGF0ZWQpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcubGVuZ3RoID0gMTB9CiMgUEJBTktBLTA4MjgwMDAgICAgICAgICBHQ1NLTy0zICBHRDEKCiMgUEJBTktBLTEzMDI3MDAgICAgICAgR0NTS08tb29tICBNRDEgCiMgUEJBTktBLTE0NDc5MDAgICAgICAgIEdDU0tPLTI5ICBNRDIKIyBQQkFOS0EtMDEwMjQwMCAgICAgICAgIEdDU0tPLTIgIE1EMyAKIyBQQkFOS0EtMDcxNjUwMCAgICAgICAgR0NTS08tMTkgIE1ENCAKIyBQQkFOS0EtMDQxMzQwMCAgICBHQ1NLTy0xMF84MjAgIE1ENQoKIyBQQkFOS0EtMTQ1NDgwMCAgICAgICAgR0NTS08tMjEgIEZEMQojIFBCQU5LQS0wOTAyMzAwICAgICAgICBHQ1NLTy0xMyAgRkQyCiMgUEJBTktBLTE0MTgxMDAgICAgICAgIEdDU0tPLTE3ICBGRDMgICAKIyBQQkFOS0EtMTQzNTIwMCAgICAgICAgR0NTS08tMjAgIEZENCAKCiMjIH4gVE9ETyB+IE1BS0UgSU5UTyBBIEZPUiBMT09QCgojIyBtYWtlIGxpc3RzIGZvciBlYWNoIGdlbm90eXBlCmNlbGxzXzE3IDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTE3IiksIF0pCmNlbGxzXzIgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMiIpLCBdKQpjZWxsc18xOSA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy0xOSIpLCBdKQpjZWxsc18yMCA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy0yMCIpLCBdKQpjZWxsc18xMyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy0xMyIpLCBdKQpjZWxsc18xMCA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy0xMF84MjAiKSwgXSkKY2VsbHNfMyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy0zIiksIF0pCmNlbGxzX29vbSA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy1vb20iKSwgXSkKY2VsbHNfMjkgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMjkiKSwgXSkKY2VsbHNfMjEgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMjEiKSwgXSkKCiMjIG1ha2UgcGxvdHMKCnBtMiA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMTcsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJmZDMiLCJcbiIsICIoUEJBTktBXzE0MTgxMDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgpwbTMgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzIsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJtZDMiLCJcbiIsICIoUEJBTktBXzAxMDI0MDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgpwbTQgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzE5LCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJtZDQiLCJcbiIsICIoUEJBTktBXzA3MTY1MDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgpwbTUgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzIwLCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiZmQ0IiwiXG4iLCAiKFBCQU5LQV8xNDM1MjAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArCiAgIyMgYWRkIHNleCBzeW1ib2xzCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy44LCB5ID0gMS41LCBsYWJlbCA9IG1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLCB5ID0gMi44LCBsYWJlbCA9IGZlbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKQoKcG02IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc18xMywgZ3JvdXAuYnkgPSAiZXhjbHVkZV9mb3Jfc2V4X3JhdGlvIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImZkMiIsIlxuIiwgIlBCQU5LQV8wOTAyMzAwIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgpwbTcgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzEwLCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgibWQ1IiwiXG4iLCAiKFBCQU5LQV8wNDEzNDAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArCiAgIyMgYWRkIHNleCBzeW1ib2xzCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy44LCB5ID0gMS41LCBsYWJlbCA9IG1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLCB5ID0gMi44LCBsYWJlbCA9IGZlbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKQoKcG04IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc18zLCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiZ2QxIiwiXG4iLCAiKFBCQU5LQV8wODI4MDAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArCiAgIyMgYWRkIHNleCBzeW1ib2xzCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy44LCB5ID0gMS41LCBsYWJlbCA9IG1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLCB5ID0gMi44LCBsYWJlbCA9IGZlbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKQoKcG05IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc19vb20sIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJtZDEiLCJcbiIsICIoUEJBTktBXzEzMDI3MDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsKICAjIyBhZGQgc2V4IHN5bWJvbHMKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAzLjgsIHkgPSAxLjUsIGxhYmVsID0gbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIsIHkgPSAyLjgsIGxhYmVsID0gZmVtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpCgpwbTEwIDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc18yOSwgZ3JvdXAuYnkgPSAiZXhjbHVkZV9mb3Jfc2V4X3JhdGlvIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIm1kMiIsIlxuIiwgIihQQkFOS0FfMTQ0NzkwMCkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgKwogICMjIGFkZCBzZXggc3ltYm9scwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDMuOCwgeSA9IDEuNSwgbGFiZWwgPSBtYWxlX3N5bWJvbCwgc2l6ZT03LCBjb2xvcj0iZ3JheSIpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMiwgeSA9IDIuOCwgbGFiZWwgPSBmZW1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikKCnBtMTEgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzIxLCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiZmQxIiwiXG4iLCAiKFBCQU5LQV8xNDU0ODAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArCiAgIyMgYWRkIHNleCBzeW1ib2xzCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMy44LCB5ID0gMS41LCBsYWJlbCA9IG1hbGVfc3ltYm9sLCBzaXplPTcsIGNvbG9yPSJncmF5IikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyLCB5ID0gMi44LCBsYWJlbCA9IGZlbWFsZV9zeW1ib2wsIHNpemU9NywgY29sb3I9ImdyYXkiKQoKIyMgcGxvdCBjb21wb3NpdGUgcGxvdAojIyBub3QgdXNlZCBhcyBvdXRzaWRlIHBsb3RzIGhhdmUgb2RkIHNpemVzCiNwbTEgKyBwbTIgKyBwbTQgKyBwbTUgKyBwbTExICsgcG03ICsgcG02ICsgcG04ICsgcG05ICsgcG0xMCArIHBtMwoKIyMgcGxvdCBjb21wb3NpdGUgcGxvdAptdXRhbnRfY2VsbF9sb2NhdGlvbnMgPC0gcGxvdF9ncmlkKHBtMiArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtNCArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtNSArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtMTEgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTcgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTYgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTggKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTkgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTEwICsgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMCwgMCwgMCksICJjbSIpKSwgcG0zKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBucm93ID0gMykKCiMjIHByaW50Cm11dGFudF9jZWxsX2xvY2F0aW9ucwpgYGAKCnNhdmUKYGBge3J9Cmdnc2F2ZSgiLi4vaW1hZ2VzX3RvX2V4cG9ydC9tZXJnZV91bWFwX211dGFudF9jZWxsX2xvY2F0aW9ucy5wbmciLCBwbG90ID0gbXV0YW50X2NlbGxfbG9jYXRpb25zLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAzMCwgaGVpZ2h0ID0gMzAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyBGaWd1cmUuIFN1cC4gRG90IFBsb3QgRmlndXJlcwoKIyMjIyBFeHByZXNzaW9uIG9mIE1hcmtlciBHZW5lcyBieSBDbHVzdGVyCgpXZSB3aWxsIHVzZSB0aGUgZm9sbG93aW5nIG1hcmtlciBnZW5lczoKYGBge3J9CiMgUEJBTktBLTEzMTk1MDAgLSBDQ1AyIC0gZmVtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0wNDE2MTAwIC0gTUcxIC0gZHluZW5pbiBoZWF2eSBjaGFpbiAtIG1hbGUgLSB1c2VkIGluIDgyMCBsaW5lCiMgUEJBTktBLTA4MzEwMDAgLSBNU1AxIC0gbGF0ZSBhc2V4dWFsCiMgUEJBTktBLTExMDIyMDAgLSBNU1A4IC0gZWFybHkgYXNleHVhbCAoZnJvbSBCb3pkZWNoIHBhcGVyKQojIFBCQU5LQS0xNDM3NTAwIC0gQVAyRyAtIGNvbW1pdG1lbnQKYGBgCgpwbG90IGV4cHJlc3Npb24gb2YgdGhlc2UgbWFya2VyIGdlbmVzIGluIGVhY2ggY2x1c3RlcgpgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodD0gOX0KIyMgY29weSB0aGUgY2x1c3RlcnMgc28geW91IGRvbid0IHBlcm1hbmVudGx5IGVkaXQgdGhlIG1hc3Rlcgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnd0QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnNfcGxvdHRpbmcgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzCgojIyByZW9yZGVyIHRoZSBsZXZlbHMgc28geW91IGNhbiBwbG90IHRoZSBjbHV0ZXJzIGFzIHlvdSB3aXNoCm15X2xldmVscyA8LSBjKGFzZXhfY2x1c3RlcnMsIGJpcG90ZW50aWFsX2NsdXN0ZXJzLCBtYWxlX2NsdXN0ZXJzLCBmZW1hbGVfY2x1c3RlcnMpCgojIyByZW9yZGVyIHRoZSBsZXZlbHMKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIDwtIGZhY3Rvcih4ID0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nLCBsZXZlbHMgPSBteV9sZXZlbHMpCgojIyBwbG90CmRvdF9wbG90X21hcmtlcnMgPC0gRG90UGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnd0LCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0xMzE5NTAwIiwgIlBCQU5LQS0wNDE2MTAwIiwgIlBCQU5LQS0xNDM3NTAwIiwgIlBCQU5LQS0wODMxMDAwIiwgIlBCQU5LQS0xMTAyMjAwIiksIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVyc19wbG90dGluZyIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogICMgY2hhbmdlIGFwcGVhcmFuY2UgYW5kIHJlbW92ZSBheGlzIGVsZW1lbnRzLCBhbmQgbWFrZSByb29tIGZvciBhcnJvd3MKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTE2LCBhbmdsZSA9IDQ1LCBoanVzdD0xLHZqdXN0PTEsIGZhbWlseSA9ICJBcmlhbCIpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2LCBmYW1pbHk9IkFyaWFsIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBsZWdlbmQuYm94ID0gInZlcnRpY2FsIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMSwzLDEsMyksICJsaW5lcyIpKSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIiwgYmVnaW4gPSAwLCBlbmQgPSAxLCBkaXJlY3Rpb24gPSAxKSArCiAgIyMgY2hhbmdlIHggYXhpcyBsYWJlbAogIGxhYnMoeCA9ICJNYXJrZXIgR2VuZXMiLCB5ID0gIkNsdXN0ZXIiLCB0aXRsZSA9ICJFeHByZXNzaW9uIG9mIE1hcmtlciBHZW5lcyBieSBDbHVzdGVyIikgKwogICMjIGFkZCBhcnJvd3MKICAjYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gNS41LCB4ZW5kID0gNS41LCB5ID0gMjEuNSwgeWVuZCA9IDI1LCBjb2xvdXIgPSAiZ3JlZW4iLCBzaXplPTEsIGFscGhhPTEsIGFycm93PWFycm93KGxlbmd0aD11bml0KDAuMzAsImNtIiksIHR5cGUgPSAiY2xvc2VkIikpICsKICAjYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gNS41LCB4ZW5kID0gNS41LCB5ID0gMTYuNSwgeWVuZCA9IDIxLjUsIGNvbG91ciA9ICJyZWQiLCBzaXplPTEsIGFscGhhPTEsIGFycm93PWFycm93KGxlbmd0aD11bml0KDAuMzAsImNtIiksIHR5cGUgPSAiY2xvc2VkIikpICsKICAjYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gNS41LCB4ZW5kID0gNS41LCB5ID0gMCwgeWVuZCA9IDE1LjUsIGNvbG91ciA9ICJncmV5Iiwgc2l6ZT0xLCBhbHBoYT0xLCBhcnJvdz1hcnJvdyhsZW5ndGg9dW5pdCgwLjMwLCJjbSIpLCB0eXBlID0gImNsb3NlZCIpKSArCiAgIyMgYW5ub3RhdGUgYXNleAogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAobGVuZ3RoKGFzZXhfY2x1c3RlcnMpKzAuNSkpKSArCiAgIyMgYW5ub3RhdGUgYmlwb3RlbnRpYWwKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gKGxlbmd0aChjKGFzZXhfY2x1c3RlcnMsIGJpcG90ZW50aWFsX2NsdXN0ZXJzKSkrMC41KSkpICsKICAjIyBhbm5vdGF0ZSBzZXhlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAobGVuZ3RoKGMoYXNleF9jbHVzdGVycywgYmlwb3RlbnRpYWxfY2x1c3RlcnMsIG1hbGVfY2x1c3RlcnMpKSswLjUpKSkgKwogICMjIGNoYW5nZSBsYWJlbCBvbiBib3R0b20gb2YgcGxvdCBzbyB3ZSBjYW4gaW5kaWNhdGUgbWFya2VycwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gcmV2KGMocGFzdGUoIlBCQU5LQS0xMTAyMjAwIiwiXG4iLCAiKE1TUDg7IGVhcmx5IGFzZXh1YWwpIiksIHBhc3RlKCJQQkFOS0EtMDgzMTAwMCIsIlxuIiwgIihNU1AxOyBsYXRlIGFzZXh1YWwpIiksIHBhc3RlKCJQQkFOS0EtMTQzNzUwMCIsICJcbiIsICIoQVAyRzsgc2V4dWFsIGNvbW1pdG1lbnQpIiksIHBhc3RlKCJQQkFOS0EtMDQxNjEwMCIsICJcbiIsICIoTUcxOyBtYWxlKSIpLCBwYXN0ZSgiUEJBTktBLTEzMTk1MDAiLCAiXG4iLCAiKENDUDI7IGZlbWFsZSkiKSkpKQoKIyMgdmlldwpwcmludChkb3RfcGxvdF9tYXJrZXJzKQpgYGAKCiMjIyMgRXhwcmVzc2lvbiBvZiB0aGUgbXV0YW50IGdlbmVzIGJ5IGNsdXN0ZXIKCmdlbmUgaWRlbnRpdGllcyBmb3IgdGhlIG11dGFudHMgcHJvZmlsZWQKYGBge3J9CiMgUEJBTktBLTA4MjgwMDAgICAgICAgICBHQ1NLTy0zICBHRDEKCiMgUEJBTktBLTEzMDI3MDAgICAgICAgR0NTS08tb29tICBNRDEgCiMgUEJBTktBLTE0NDc5MDAgICAgICAgIEdDU0tPLTI5ICBNRDIKIyBQQkFOS0EtMDEwMjQwMCAgICAgICAgIEdDU0tPLTIgIE1EMyAKIyBQQkFOS0EtMDcxNjUwMCAgICAgICAgR0NTS08tMTkgIE1ENCAKIyBQQkFOS0EtMDQxMzQwMCAgICBHQ1NLTy0xMF84MjAgIE1ENQoKIyBQQkFOS0EtMTQ1NDgwMCAgICAgICAgR0NTS08tMjEgIEZEMQojIFBCQU5LQS0wOTAyMzAwICAgICAgICBHQ1NLTy0xMyAgRkQyCiMgUEJBTktBLTE0MTgxMDAgICAgICAgIEdDU0tPLTE3ICBGRDMgICAKIyBQQkFOS0EtMTQzNTIwMCAgICAgICAgR0NTS08tMjAgIEZENCAKYGBgCgpwbG90IGV4cHJlc3Npb24gb2YgdGhlc2UgbXV0YW50IGdlbmVzIGJ5IGNsdXN0ZXIKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQ9IDl9CiMjIHBsb3QKZG90X3Bsb3RfbXV0YW50X2dlbmVzIDwtIERvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC53dCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMDgyODAwMCIsICJQQkFOS0EtMTMwMjcwMCIsICJQQkFOS0EtMTQ0NzkwMCIsICJQQkFOS0EtMDEwMjQwMCIsICJQQkFOS0EtMDcxNjUwMCIsIlBCQU5LQS0xNDU0ODAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDM1MjAwIiksIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVyc19wbG90dGluZyIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogICMjIGNoYW5nZSBhcHBlYXJhbmNlIGFuZCByZW1vdmUgYXhpcyBlbGVtZW50cywgYW5kIG1ha2Ugcm9vbSBmb3IgYXJyb3dzLCBhbmQgYWxzbyBjaGFuZ2UgcG9zb2l0aW9uIG9mIGxlZ2VuZHMgcmVsYXRpdmUgdG8gb25lIGFub3RoZXIKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZSA9IDQ1LCBoanVzdD0xLHZqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIsIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMywxLDMpLCAibGluZXMiKSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiwgZmFtaWx5PSJBcmlhbCIpKSArCiAgIyNhZGQgdGhlc2UgdG8gYWJvdmUgdG8gcmVtb3ZlIHkgPSBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkKICAjIyBjaGFuZ2UgdGhlIGNvbG91cnMKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhvcHRpb24gPSAiaW5mZXJubyIsIGd1aWRlID0gImNvbG91cmJhciIsIG5hLnZhbHVlPSJ3aGl0ZSIsIGJlZ2luID0gMCwgZW5kID0gMSwgZGlyZWN0aW9uID0gMSkgKwogICMjIGNoYW5nZSB4IGF4aXMgbGFiZWwKICBsYWJzKHggPSAiTXV0YW50IEdlbmVzIiwgIHRpdGxlID0gIkV4cHJlc3Npb24gb2YgbXV0YW50IGdlbmVzIGJ5IGNsdXN0ZXIiLCB5ID0gIkNsdXN0ZXIiKSArCiAgIyMgYW5ub3RhdGUgYXNleAogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAobGVuZ3RoKGFzZXhfY2x1c3RlcnMpKzAuNSkpKSArCiAgIyMgYW5ub3RhdGUgYmlwb3RlbnRpYWwKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gKGxlbmd0aChjKGFzZXhfY2x1c3RlcnMsIGJpcG90ZW50aWFsX2NsdXN0ZXJzKSkrMC41KSkpICsKICAjIyBhbm5vdGF0ZSBzZXhlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAobGVuZ3RoKGMoYXNleF9jbHVzdGVycywgYmlwb3RlbnRpYWxfY2x1c3RlcnMsIG1hbGVfY2x1c3RlcnMpKSswLjUpKSkgKwogICMjIGNoYW5nZSBsYWJlbCBvbiBib3R0b20gb2YgcGxvdCBzbyB3ZSBjYW4gaW5kaWNhdGUgbWFya2VycwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gcmV2KGMocGFzdGUoIlBCQU5LQS0xNDM1MjAwIiwgIlxuIiwgImZkNCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0wNDEzNDAwIiwiXG4iLCAibWQ1IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiUEJBTktBLTA5MDIzMDAiLCAiXG4iLCAiZmQyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiUEJBTktBLTE0MTgxMDAiLCAiXG4iLCAiZmQzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiUEJBTktBXzE0NTQ4MDAiLCJcbiIsICJmZDEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJQQkFOS0EtMDcxNjUwMCIsICJcbiIsICJtZDQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJQQkFOS0EtMDEwMjQwMCIsICJcbiIsICJtZDMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJQQkFOS0EtMTQ0NzkwMCIsICJcbiIsICJtZDIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJQQkFOS0EtMTMwMjcwMCIsICJcbiIsICJtZDEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJQQkFOS0EtMDgyODAwMCIsICJcbiIsICJnZDEiKSkpKQoKIyMgdmlldwpwcmludChkb3RfcGxvdF9tdXRhbnRfZ2VuZXMpCmBgYAoKIyMjIyBSZXByZXNlbnRhdGlvbiBvZiBFeHBlcmltZW50IGJ5IENsdXN0ZXIKCm1ha2UgYSBtZXRhZGF0YSBjb2x1bW4gd2hlcmUgdGhlIDEwWCBkYXRhIGlzIGNsYXNzaWZpZWQgYXMgYSBXVCBnZW5vdHlwZQpgYGB7cn0KIyMgZ2V0IGNlbGxzIHRoYXQgYXJlIGZpbHRlcmVkIG91dApjZWxsc18xMHggPC0gd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkZXhwZXJpbWVudCA9PSAidGVueF81ayIpCgojIyBtYWtlIGV4dHJhIGNvbHVtbiBpbiBwbG90dGluZyBkZgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRnZW5vdHlwZV9jb21iaW5lZCA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRnZW5vdHlwZQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRnZW5vdHlwZV9jb21iaW5lZFtjZWxsc18xMHhdIDwtICJXVCIKCiMjIGluc3BlY3QKdGFibGUodGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWQpCmBgYAoKUGxvdCBleHByZXNzaW9uIG9mIG11dGFudCBnZW5lcyBieSBjbHVzdGVyICh3aGljaCBpcyBzdWJkaXZpZGVkIGJ5IGdlbm90eXBlKQoKVGhpcyBpcyBraW5kIG9mIGEgY29udHJvbCBiZWNhdXNlIHRoZSBtdXRhbnQgc2hvdWxkIGV4cHJlc3MgbGVzcyBvZiB0aGUgZ2VuZSBvZiBpbnRlcmVzdCBhdCBzb21lIHBvaW50IGR1ZSB0byB0aGUgaW5jbHVzaW9uIG9mIHRoZSBtdXRhbnQgY2VsbHMKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQ9IDEyfQojIyBwbG90CmRvdF9wbG90X211dGFudF9nZW5lc19nZW5vdHlwZSA8LSBEb3RQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gYygiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTE0NTQ4MDAiKSwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIiwgc3BsaXQuYnkgPSAiZ2Vub3R5cGVfY29tYmluZWQiKSArCiAgIyMgbWFrZSBhcHBlYXJhbmNlIHNtb290aGVyCiAgdGhlbWVfY2xhc3NpYygpICsKICAjIyBjaGFuZ2UgYXBwZWFyYW5jZSBhbmQgcmVtb3ZlIGF4aXMgZWxlbWVudHMsIGFuZCBtYWtlIHJvb20gZm9yIGFycm93cwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIGFuZ2xlID0gNDUsIGhqdXN0PTEsdmp1c3Q9MSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwxKSwgImxpbmVzIikpICsKICAjIyBjaGFuZ2UgdGhlIGNvbG91cnMKICAjc2NhbGVfY29sb3VyX3ZpcmlkaXMob3B0aW9uID0gImluZmVybm8iLCBndWlkZSA9ICJjb2xvdXJiYXIiLCBuYS52YWx1ZT0id2hpdGUiLCBiZWdpbiA9IDAsIGVuZCA9IDEsIGRpcmVjdGlvbiA9IDEpICsKICAjIyBjaGFuZ2UgeCBheGlzIGxhYmVsCiAgbGFicyh4ID0gIk1hcmtlciBHZW5lcyIpICsKICAjIyBhbm5vdGF0ZSBtYWxlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSA1Ni41KSkgKwogICMjIGFubm90YXRlIGZlbWFsZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gNDguNSkpICsKICAjIyBhbm5vdGF0ZSBoZXJtYXBocm9kaXRlCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDQ2LjUpKQogICMjIGNoYW5nZSBsYWJlbCBvbiBib3R0b20gb2YgcGxvdCBzbyB3ZSBjYW4gaW5kaWNhdGUgbWFya2VycwogICNzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMocGFzdGUoIlBCQU5LQS0xMTAyMjAwIiwiXG4iLCAiKE1TUDg7IGVhcmx5IGFzZXh1YWwpIiksIHBhc3RlKCJQQkFOS0EtMDgzMTAwMCIsIlxuIiwgIihNU1AxOyBsYXRlIGFzZXh1YWwpIiksIHBhc3RlKCJQQkFOS0EtMTQzNzUwMCIsICJcbiIsICIoQVAyRzsgc2V4dWFsIGNvbW1pdG1lbnQpIiksIHBhc3RlKCJQQkFOS0EtMDQxNjEwMCIsICJcbiIsICIoTUcxOyBtYWxlKSIpLCBwYXN0ZSgiUEJBTktBLTEzMTk1MDAiLCAiXG4iLCAiKENDUDI7IGZlbWFsZSkiKSkpCgojIyB2aWV3CnByaW50KGRvdF9wbG90X211dGFudF9nZW5lc19nZW5vdHlwZSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodD0gMTJ9CiMjIHBsb3QKZG90X3Bsb3RfbXV0YW50c19leHBlcmltZW50IDwtIERvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMDgyODAwMCIsICJQQkFOS0EtMTMwMjcwMCIsICJQQkFOS0EtMTQ0NzkwMCIsICJQQkFOS0EtMDEwMjQwMCIsICJQQkFOS0EtMDcxNjUwMCIsICJQQkFOS0EtMTQzNTIwMCIsICJQQkFOS0EtMTQxODEwMCIsICJQQkFOS0EtMTE0NDgwMCIsICJQQkFOS0EtMDkwMjMwMCIsICJQQkFOS0EtMDQxMzQwMCIsICJQQkFOS0EtMTQ1NDgwMCIpLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnNfcGxvdHRpbmciLCBzcGxpdC5ieSA9ICJzdWJfZ2Vub3R5cGUiLCBjb2xzID0gYygicmVkIiwgImJsdWUiLCAiZ3JlZW4iKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyBjaGFuZ2UgYXBwZWFyYW5jZSBhbmQgcmVtb3ZlIGF4aXMgZWxlbWVudHMsIGFuZCBtYWtlIHJvb20gZm9yIGFycm93cwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIGFuZ2xlID0gNDUsIGhqdXN0PTEsdmp1c3Q9MSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwxKSwgImxpbmVzIikpICsKICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgI3NjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIiwgYmVnaW4gPSAwLCBlbmQgPSAxLCBkaXJlY3Rpb24gPSAxKSArCiAgIyMgY2hhbmdlIHggYXhpcyBsYWJlbAogIGxhYnMoeCA9ICJNYXJrZXIgR2VuZXMiKSArCiAgIyMgYW5ub3RhdGUgbWFsZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gNzcpKSArCiAgIyMgYW5ub3RhdGUgZmVtYWxlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSA2MSkpICsKICAjIyBhbm5vdGF0ZSBoZXJtYXBocm9kaXRlCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDU5KSkKICAjIyBjaGFuZ2UgbGFiZWwgb24gYm90dG9tIG9mIHBsb3Qgc28gd2UgY2FuIGluZGljYXRlIG1hcmtlcnMKICAjc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKHBhc3RlKCJQQkFOS0EtMTEwMjIwMCIsIlxuIiwgIihNU1A4OyBlYXJseSBhc2V4dWFsKSIpLCBwYXN0ZSgiUEJBTktBLTA4MzEwMDAiLCJcbiIsICIoTVNQMTsgbGF0ZSBhc2V4dWFsKSIpLCBwYXN0ZSgiUEJBTktBLTE0Mzc1MDAiLCAiXG4iLCAiKEFQMkc7IHNleHVhbCBjb21taXRtZW50KSIpLCBwYXN0ZSgiUEJBTktBLTA0MTYxMDAiLCAiXG4iLCAiKE1HMTsgbWFsZSkiKSwgcGFzdGUoIlBCQU5LQS0xMzE5NTAwIiwgIlxuIiwgIihDQ1AyOyBmZW1hbGUpIikpKQoKIyMgdmlldwpwcmludChkb3RfcGxvdF9tdXRhbnRzX2V4cGVyaW1lbnQpCmBgYAoKIyMjIyBSZXByZXNlbnRhdGlvbiBvZiBtdXRhbnRzIGluIGNsdXN0ZXJzCgpBZGQgYSBtZXRhLmRhdGEgY29sdW1uIHNvIHRoYXQgMTBYIGlzIGxpc3RlZCBhcyBXVDoKYGBge3J9CiMjIGdldCBjZWxscyB0aGF0IGFyZSBmaWx0ZXJlZCBvdXQKbXV0YW50X2NlbGxzIDwtIHdoaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQkZXhwZXJpbWVudCA9PSAibXV0YW50cyIpCgojIyBtYWtlIGV4dHJhIGNvbHVtbiBpbiBwbG90dGluZyBkZgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA8LSAiV1RfMTBYIgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZFttdXRhbnRfY2VsbHNdIDwtIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWRbbXV0YW50X2NlbGxzXQpgYGAKCnByZXBhcmUgZGF0YSBmb3IgZG90cGxvdHRpbmcKYGBge3J9CiMjIG1ha2UgYSBkYXRhZnJhbWUgdGhhdCBpcyBhIGNvcHkgb2YgdGhlIG1ldGEgZGF0YQpkZl9tZXRhX2RhdGEgPC0gYXMuZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSkKCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzOgpkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzIDwtIGZhY3Rvcih4ID0gZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgbGV2ZWxzID0gbXlfbGV2ZWxzKQoKIyMgbWFrZSBhIG5ldyBkZiBvZiBDTFVTVEVSIGFuZCBJREVOVElUWQpkb3RfcGxvdF9kZiA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZShkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfY29tYmluZWQpKQpkb3RfcGxvdF9kZiRjbHVzdGVyIDwtIHJvd25hbWVzKGRvdF9wbG90X2RmKQoKIyMgY2FsY3VsYXRlIHBlcmNlbnRhZ2Ugb2YgY2VsbHMgZm9yIGVhY2ggZ2Vub3R5cGUKZG90X3Bsb3RfZGZfcGMgPC0gKGFzLmRhdGEuZnJhbWUubWF0cml4KHByb3AudGFibGUodGFibGUoZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgZGZfbWV0YV9kYXRhJGlkZW50aXR5X2NvbWJpbmVkKSwgbWFyZ2luID0gMikpICogMTAwKQoKIyMgbWFrZSBhIGNvbHVtbiBmb3IgY2x1c3RlciBuYW1lcwpkb3RfcGxvdF9kZl9wYyRjbHVzdGVyIDwtIHJvd25hbWVzKGRvdF9wbG90X2RmX3BjKQoKIyMgbWVsdCBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nCmxpYnJhcnkocmVzaGFwZTIpCmRvdF9wbG90X2RmX3BjX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmX3BjLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9wY19tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKCiMjIG1lbHQgdGhlIHJhdyBudW1iZXIgdG9vCmRvdF9wbG90X2RmX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKY29sbmFtZXMoZG90X3Bsb3RfZGZfbWVsdGVkKVszXSA8LSAicmF3X251bWJlciIKCiMjIG1lcmdlIHRvZ2V0aGVyCmlkZW50aWNhbChkb3RfcGxvdF9kZl9tZWx0ZWQkY2x1c3RlciwgZG90X3Bsb3RfZGZfcGNfbWVsdGVkJGNsdXN0ZXIpCmRvdF9wbG90X21lcmdlZCA8LSBjYmluZChkb3RfcGxvdF9kZl9tZWx0ZWQsIGRvdF9wbG90X2RmX3BjX21lbHRlZCkKZG90X3Bsb3RfbWVyZ2VkIDwtIGRvdF9wbG90X21lcmdlZFssYygxLDIsMyw2KV0KCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzCmRvdF9wbG90X21lcmdlZCRjbHVzdGVyIDwtIGZhY3Rvcih4ID0gZG90X3Bsb3RfbWVyZ2VkJGNsdXN0ZXIsIGxldmVscyA9IG15X2xldmVscykKCiMjIHdoZXJlIHZhbHVlcyBhcmUgemVybywgYWRkIE5BCiMjIGZpbmQgd2VsbHMgd2hlcmUgaXQncyB6ZXJvCnplcm9fdmFsdWVzIDwtIGRvdF9wbG90X21lcmdlZCR2YWx1ZSA9PSAwCmRvdF9wbG90X21lcmdlZCR2YWx1ZVt6ZXJvX3ZhbHVlc10gPC0gTkEKCiMjIGFsc28gZG8gZm9yIHJhdyBudW1iZXIKemVyb192YWx1ZXMgPC0gZG90X3Bsb3RfbWVyZ2VkJHJhd19udW1iZXIgPT0gMApkb3RfcGxvdF9tZXJnZWQkcmF3X251bWJlclt6ZXJvX3ZhbHVlc10gPC0gTkEKCiMjIHJlb3JkZXIgeCBheGlzOgpteV9sZXZlbHNfZ2Vub3R5cGUgPC0gYygiR0NTS08tb29tIiwgIkdDU0tPLTI5IiwgIkdDU0tPLTMiLCAiR0NTS08tMiIsICJHQ1NLTy0xOSIsICJHQ1NLTy0yOCIsICJHQ1NLTy0yMSIsICJHQ1NLTy0xMyIsICJHQ1NLTy0xNyIsICJHQ1NLTy0yMCIsICJHQ1NLTy0xMF84MjAiLCAiV1QiLCAiV1RfMTBYIikKCmRvdF9wbG90X21lcmdlZCRpZGVudGl0eSA8LSBmYWN0b3IoeCA9IGRvdF9wbG90X2RmX3BjX21lbHRlZCRpZGVudGl0eSwgbGV2ZWxzID0gbXlfbGV2ZWxzX2dlbm90eXBlKQpgYGAKCnBsb3QKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQ9IDd9CmRvdF9wbG90X2lkZW50aXR5IDwtIGdncGxvdChkb3RfcGxvdF9tZXJnZWQsIGFlcyh5ID0gZmFjdG9yKGNsdXN0ZXIpLCB4ID0gZmFjdG9yKGlkZW50aXR5KSkpICsKICAgICAgIyMgbWFrZSBpbnRvIGEgZG90IHBsb3QKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3VyPXZhbHVlLCBzaXplPXJhd19udW1iZXIpKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImJsdWUiLCBoaWdoPSJyZWQiLCBsaW1pdHM9YyggMCwgbWF4KGRvdF9wbG90X2RmX3BjX21lbHRlZCR2YWx1ZSkpLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgICNjaGFuZ2UgdGhlIGNvbG91cnMKICAgICAgc2NhbGVfY29sb3VyX3ZpcmlkaXMob3B0aW9uID0gImluZmVybm8iLCBndWlkZSA9ICJjb2xvdXJiYXIiLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSkgKwogICAgICB5bGFiKCJDbHVzdGVyIikgKwogICAgICB4bGFiKCJJZGVudGl0eSIpICsKICAgICAgbGFicyhjb2xvdXIgPSAiJSBjZWxscyBvZiB0aGF0IGdlbm90eXBlIHJlcHJlc2VudGVkIGluIHRoYXQgY2x1c3RlciIsIHNpemUgPSAibnVtYmVyIG9mIGNlbGxzIG9mIHRoYXQgZ2Vub3R5cGUgcmVwcmVzZW50ZWQgaW4gdGhhdCBjbHVzdGVyIikgKwogICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiwgYW5nbGU9NDUsIGhqdXN0PTEsIHZqdXN0PTEpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBsZWdlbmQuYm94ID0gInZlcnRpY2FsIiwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiwgIGZhbWlseT0iQXJpYWwiKSkgKwogICMjIGFubm90YXRlIGFzZXgKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gKGxlbmd0aChhc2V4X2NsdXN0ZXJzKSswLjUpKSkgKwogICMjIGFubm90YXRlIGJpcG90ZW50aWFsCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IChsZW5ndGgoYyhhc2V4X2NsdXN0ZXJzLCBiaXBvdGVudGlhbF9jbHVzdGVycykpKzAuNSkpKSArCiAgIyMgYW5ub3RhdGUgc2V4ZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gKGxlbmd0aChjKGFzZXhfY2x1c3RlcnMsIGJpcG90ZW50aWFsX2NsdXN0ZXJzLCBtYWxlX2NsdXN0ZXJzKSkrMC41KSkpCiN0aXRsZSA9ICIlIGdlbm90eXBlIHBvcHVsYXRpb24gZm91bmQgaW4gZWFjaCBjbHVzdGVyIiwgCgpwcmludChkb3RfcGxvdF9pZGVudGl0eSkKYGBgCgptYXliZSB0aGUgcmVzcHJlc2VudGF0aW9uIGRpZmZlcmVuY2VzIGhhdmUgYmF0Y2gtZWZmZWN0czoKYGBge3J9CiN0YWJsZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzb3J0X2RhdGUsIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQpCmBgYAoKIyMjIyBDb21wb3NlIEZpbmFsIFBsb3QKYGBge3IsIGZpZy53aWR0aCA9IDE0LCBmaWcuaGVpZ2h0ID0gMTJ9CmRvdF9wbG90X2lkZW50aXR5ICsgZG90X3Bsb3RfbWFya2VycyArIGRvdF9wbG90X211dGFudF9nZW5lcwpgYGAKCiMgOC4gU3Vic2V0IHNleHVhbCBjZWxscyB7LnRhYnNldH0KCk1ha2UgYSBzdWJzZXR0ZWQgU2V1cmF0IG9iamVjdCBvZiBzZXh1YWwgY2VsbHMuIAoKSW5jbHVkZSB0aGUgcHJlLWJyYW5jaCB0b28gYXMgd2VsbCBhcyBhbnkgd2VpcmQgY2x1c3RlcnMgdGhhdCBtYXkgaGF2ZSBjbHVzdGVyZWQgb3V0LiAKCml0J3MgYmVlbiBhIHdoaWxlIHNpbmNlIHdlIGxvb2tlZCBhdCB0aGUgY2x1c3RlcnMgc28gbGV0J3MgY2hlY2sgdGhlbSBvdXQgYWdhaW46CmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyBjb29yZF9maXhlZCgpCmBgYAoKIyMjIERlZmluZSBjZWxscyBhbmQgc3Vic2V0CmBgYHtyfQojIyBkZWZpbmUgY2VsbHMKIyMgMiBhbmQgMCBhcmUgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc3RhbGsKc2V4X2NsdXN0ZXJzIDwtIGMoYmlwb3RlbnRpYWxfY2x1c3RlcnMsIGZlbWFsZV9jbHVzdGVycywgbWFsZV9jbHVzdGVycywgIjUiLCAiNyIpCgojIyBzdWJzZXQgY2VsbHMgaW50byBuZXcgb2JqZWN0CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIHN1YnNldCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBpZGVudHMgPSBzZXhfY2x1c3RlcnMpCmBgYAoKIyMjIGluc3BlY3QvY2hlY2sKYGBge3J9CiMjIGluc3BlY3Qgb2JqZWN0CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4CgojIyBsb29rIGF0IG9yaWdpbmFsIFVNQVAKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIGNvb3JkX2ZpeGVkKCkKYGBgCgojIyMjIFJlbW92ZSBjb250YW1pbmFudCBhc2V4dWFsIGNlbGxzCgp3ZSB3YW50IHRvIHJlbW92ZToKYGBge3J9CiMjIGxvb2sgYXQgb3JpZ2luYWwgVU1BUApwbG90X3NleHVhbF9zdWJzZXR0aW5nIDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIGNvb3JkX2ZpeGVkKCkgKyBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gLTAuODAsIGFscGhhID0gNSkpICsgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IC0wLjEsIGFscGhhID0gNSkpCgpwbG90X3NleHVhbF9zdWJzZXR0aW5nCmBgYAoKTG9vayBpbnRlcmFjdGl2ZWx5OgoKYGBge3J9CkhvdmVyTG9jYXRvcihwbG90ID0gcGxvdF9zZXh1YWxfc3Vic2V0dGluZywgaW5mb3JtYXRpb24gPSBGZXRjaERhdGEob2JqZWN0ID0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHZhcnMgPSAnaWRlbnRpdHlfbmFtZV91cGRhdGVkJykpCmBgYAoKCmBgYHtyfQojIyBleHRyYWN0IGNlbGwgZW1iZWRkaW5ncwpkZl9zZXhfY2VsbF9lbWJlZGRpbmdzIDwtIGFzLmRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAcmVkdWN0aW9uc1tbIkRJTV9VTUFQIl1dQGNlbGwuZW1iZWRkaW5ncykKCiMjIHN1YnNldCBhbnl0aGluZyBsb3dlciB0aGFuIC0wLjggaW4gVU1BUCAyIGFuZCAtMC4xIGluIFVNQVAgMQpyZW1vdmVfY2VsbHMgPC0gcm93Lm5hbWVzKGRmX3NleF9jZWxsX2VtYmVkZGluZ3Nbd2hpY2goZGZfc2V4X2NlbGxfZW1iZWRkaW5ncyRESU1VTUFQXzIgPCAtMC4xIHwgZGZfc2V4X2NlbGxfZW1iZWRkaW5ncyRESU1VTUFQXzEgPCAtMC44KSwgXSkKCiMjIHBsb3QgdGhlc2UgY2VsbHMKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSByZW1vdmVfY2VsbHMsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJjZWxscyBoaWdobGlnaHRlZCB3aWxsIGJlIHJlbW92ZWQiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCmBgYHtyfQpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAxLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBncm91cC5ieSA9ICJpZGVudGl0eV9jb21iaW5lZCIpICsgCiAgY29vcmRfZml4ZWQoKSAKYGBgCgoKdGhlbiBjaGVjayB3aGF0IHRoZSBJRHMgb2YgdGhlc2UgY2VsbHMgYXJlIHRvIGVuc3VyZSB0aGV5IGFyZW4ndCBhIGdlbnVpbmUgbXV0YW50IHNpZ25hdHVyZQpgYGB7cn0KdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3Jvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSkgJWluJSByZW1vdmVfY2VsbHMsIF0kaWRlbnRpdHlfY29tYmluZWQKYGBgCgpBbHRob3VnaCB0aGVyZSBhcmUgYSBudW1iZXIgb2YgR0NTS08tMjEgY2VsbHMsIHRoZXJlIGFyZSBzdGlsbCBtYW55IHJlbWFpbmluZyBpbiB0aGUgc2V4IGNsdXN0ZXIgYWJvdmUgYW5kIHRoZSBjZWxscyBuZWFyIHRoZSBhc2V4dWFsIGN5Y2xlIGFsc28gaGF2ZSBhIEdDU0tPLTE3IGNlbGwgd2l0aCB0aGVtIGFuZCBhcmUgdGhlcmVmb3JlIG5vdCBleGNsdXNpdmVseSBiZWxvbmdpbmcgdG8gdGhhdCBtdXRhbnQgc28gd2Ugd2lsbCByZW1vdmUgdGhlc2UgY2VsbHMuIAoKIyMgRmluYWwgU3Vic2V0CmBgYHtyfQojIyBtYWtlIGtlZXAgY2VsbHMgZnJvbSB0aGUgcmVtb3ZlX2NlbGxzCiMjIG1ha2UgdGhlIG5vdCBpbiBmdW5jdGlvbgonJW5pJScgPC0gTmVnYXRlKCclaW4lJykKa2VlcF9jZWxscyA8LSBjb2xuYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleClbd2hpY2goY29sbmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgpICVuaSUgcmVtb3ZlX2NlbGxzKV0KCiMjIHN1YnNldAp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBzdWJzZXQodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0ga2VlcF9jZWxscykKCiMjIGluc3BlY3QKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgKYGBgCgpjb3B5IG9sZCBjbHVzdGVycyBvdmVyCmBgYHtyfQojIyBjb3B5IG9sZCBjbHVzdGVycwp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBBZGRNZXRhRGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycywgY29sLm5hbWUgPSAicG9zdF9pbnRlZ3JhdGlvbl9jbHVzdGVycyIpCmBgYAoKIyA5LiBQc2V1ZG90aW1lIG9uIGFsbCBjZWxscyB7LnRhYnNldH0KCiMjIyBQc2V1ZG90aW1lIGNhbGN1bGF0aW9uCgpgYGB7cn0KIyMgZXh0cmFjdCBkYXRhIGZyb20gU2V1cmF0CnNldXJhdC5vYmplY3QuYWxsIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQKIyBjb3VudHMKZGF0YSA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHNldXJhdC5vYmplY3QuYWxsLCBhc3NheSA9ICJpbnRlZ3JhdGVkIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKIyBtZXRhIGRhdGEKcGQgPC0gZGF0YS5mcmFtZShzZXVyYXQub2JqZWN0LmFsbEBtZXRhLmRhdGEpCgojIyBrZWVwIG9ubHkgdGhlIGNvbHVtbnMgdGhhdCBhcmUgcmVsZXZhbnQKI3BEYXRhIDwtIHBkICU+JSBzZWxlY3Qob3JpZy5pZGVudCwgbkNvdW50X1JOQSwgbkZlYXR1cmVfUk5BKQojIyBhZGQgZ2VuZSBzaG9ydCBuYW1lCmZEYXRhIDwtIGRhdGEuZnJhbWUoZ2VuZV9zaG9ydF9uYW1lID0gcm93Lm5hbWVzKGRhdGEpLCByb3cubmFtZXMgPSByb3cubmFtZXMoZGF0YSkpCgojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKbW9ub2NsZS5vYmplY3QuYWxsIDwtIG5ld19jZWxsX2RhdGFfc2V0KGV4cHJlc3Npb25fZGF0YSA9IGRhdGEsIGNlbGxfbWV0YWRhdGEgPSBwZCwgZ2VuZV9tZXRhZGF0YSA9IGZEYXRhKQojIyBwcmVwcm9jZXNzCm1vbm9jbGUub2JqZWN0LmFsbCA9IHByZXByb2Nlc3NfY2RzKG1vbm9jbGUub2JqZWN0LmFsbCwgbnVtX2RpbSA9IDEwMCwgbm9ybV9tZXRob2QgPSAibm9uZSIpCiMjIHBsb3QgdmFyaWFuY2UgZXhwbGFpbmVkIHBsb3QKcGxvdF9wY192YXJpYW5jZV9leHBsYWluZWQobW9ub2NsZS5vYmplY3QuYWxsKQojIyBtYWtlIG1vbm9jbGUgVU1BUAojbW9ub2NsZS5vYmplY3QuYWxsID0gcmVkdWNlX2RpbWVuc2lvbihtb25vY2xlLm9iamVjdC5hbGwsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIsIHByZXByb2Nlc3NfbWV0aG9kID0gIlBDQSIsIHVtYXAubWV0cmljID0gImV1Y2xpZGVhbiIsIHVtYXAubl9uZWlnaGJvcnMgPSAyMCwgdW1hcC5taW5fZGlzdCA9IDAuNSwgdmVyYm9zZSA9IEZBTFNFKQojcGxvdF9jZWxscyhtb25vY2xlLm9iamVjdC5hbGwpCgojIyBhZGQgVU1BUCBmcm9tIFNldXJhdAptb25vY2xlLm9iamVjdC5hbGxAaW50X2NvbERhdGFAbGlzdERhdGEkcmVkdWNlZERpbXNAbGlzdERhdGFbWyJVTUFQIl1dIDwtc2V1cmF0Lm9iamVjdC5hbGxAcmVkdWN0aW9uc1tbIkRJTV9VTUFQIl1dQGNlbGwuZW1iZWRkaW5ncyAKcGxvdF9jZWxscyhtb25vY2xlLm9iamVjdC5hbGwpCgojIyBjbHVzdGVyCm1vbm9jbGUub2JqZWN0LmFsbCA9IGNsdXN0ZXJfY2VsbHMobW9ub2NsZS5vYmplY3QuYWxsKQoKIyMgcGxvdCBjbHVzdGVycwpwbG90X2NlbGxzKG1vbm9jbGUub2JqZWN0LmFsbCwgY29sb3JfY2VsbHNfYnk9InBhcnRpdGlvbiIsIGdyb3VwX2NlbGxzX2J5PSJwYXJ0aXRpb24iLCAgeCA9IDIsIHkgPSAxKQoKIyMgcmVkdWNlIHBhcnRpdGlvbnMgdG8gMQptb25vY2xlLm9iamVjdC5hbGxAY2x1c3RlcnMkVU1BUCRwYXJ0aXRpb25zW21vbm9jbGUub2JqZWN0LmFsbEBjbHVzdGVycyRVTUFQJHBhcnRpdGlvbnMgPT0gIjIiXSA8LSAiMSIKCiNtYXAgcHNldWRvdGltZQptb25vY2xlLm9iamVjdC5hbGwgPSBsZWFybl9ncmFwaChtb25vY2xlLm9iamVjdC5hbGwsIGxlYXJuX2dyYXBoX2NvbnRyb2w9bGlzdChuY2VudGVyPTUwMCksIHVzZV9wYXJ0aXRpb24gPSBGQUxTRSkKCnBsb3RfY2VsbHMobW9ub2NsZS5vYmplY3QuYWxsLCBjb2xvcl9jZWxsc19ieT0icGFydGl0aW9uIiwgZ3JvdXBfY2VsbHNfYnk9InBhcnRpdGlvbiIsICB4ID0gMiwgeSA9IDEpCgoKIyMgYSBoZWxwZXIgZnVuY3Rpb24gdG8gaWRlbnRpZnkgdGhlIHJvb3QgcHJpbmNpcGFsIHBvaW50czoKIyMgbWFrZSBjbHVzdGVyIDIgdGhlIHJvb3QKZ2V0X2VhcmxpZXN0X3ByaW5jaXBhbF9ub2RlIDwtIGZ1bmN0aW9uKGNkcywgdGltZV9iaW49IjciKXsKICBjZWxsX2lkcyA8LSB3aGljaChjb2xEYXRhKGNkcylbLCAic2V1cmF0X2NsdXN0ZXJzIl0gPT0gdGltZV9iaW4pCiAgY2xvc2VzdF92ZXJ0ZXggPC0KICBjZHNAcHJpbmNpcGFsX2dyYXBoX2F1eFtbIlVNQVAiXV0kcHJfZ3JhcGhfY2VsbF9wcm9qX2Nsb3Nlc3RfdmVydGV4CiAgY2xvc2VzdF92ZXJ0ZXggPC0gYXMubWF0cml4KGNsb3Nlc3RfdmVydGV4W2NvbG5hbWVzKGNkcyksIF0pCiAgcm9vdF9wcl9ub2RlcyA8LQogIGlncmFwaDo6VihwcmluY2lwYWxfZ3JhcGgoY2RzKVtbIlVNQVAiXV0pJG5hbWVbYXMubnVtZXJpYyhuYW1lcwogICh3aGljaC5tYXgodGFibGUoY2xvc2VzdF92ZXJ0ZXhbY2VsbF9pZHMsXSkpKSldCiAgCiAgcm9vdF9wcl9ub2Rlcwp9CgojIyBjYWxjdWxhdGUgcHNldWRvdGltZQojbW9ub2NsZS5vYmplY3QuYWxsID0gb3JkZXJfY2VsbHMobW9ub2NsZS5vYmplY3QuYWxsLCByb290X3ByX25vZGVzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShtb25vY2xlLm9iamVjdC5hbGwpKQptb25vY2xlLm9iamVjdC5hbGwgPSBvcmRlcl9jZWxscyhtb25vY2xlLm9iamVjdC5hbGwpCiMjIHVzZWQgNSBwb2ludHMgYXQgdGhlIGJlZ2lubmluZwoKCiMjIHBsb3QKdW1hcF9wdCA8LSBwbG90X2NlbGxzKG1vbm9jbGUub2JqZWN0LmFsbCwgY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIsIGxhYmVsX2NlbGxfZ3JvdXBzPUZBTFNFLCBjZWxsX3NpemUgPSAxLCB4ID0gMiwgeSA9IDEsIGxhYmVsX2JyYW5jaF9wb2ludHM9RkFMU0UsIGxhYmVsX2xlYXZlcz1GQUxTRSwgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXI9RkFMU0UsIGxhYmVsX3Jvb3RzID0gRkFMU0UpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIGxhYnModGl0bGUgPSAiIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemU9MjApLCBsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQgKHNpemU9MjApLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCkpICsgCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDEwLCBiYXJoZWlnaHQgPSAyLCB0aXRsZSA9ICJQc2V1ZG90aW1lIikpCgojIyB2aWV3IHBsb3QKdW1hcF9wdAoKIyMgaGVscCB3YXMgb2J0YWluZWQgZnJvbSBoZXJlCiMjIGh0dHBzOi8vZ2l0aHViLmNvbS9zYXRpamFsYWIvc2V1cmF0L2lzc3Vlcy8xNjU4CmBgYAoKc2F2ZQpgYGB7cn0KZ2dzYXZlKCIuLi9pbWFnZXNfdG9fZXhwb3J0L3B0X2FsbF9VTUFQX3B0LnBuZyIsIHBsb3QgPSB1bWFwX3B0LCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMjAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyBnZ2FuaW1uYXRlIEdJRiBvZiBwc2V1b2R0aW1lCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoImdnYW5pbWF0ZSIpCmxpYnJhcnkoZ2dhbmltYXRlKQojaW5zdGFsbC5wYWNrYWdlcygiZ2lmc2tpIikKI2luc3RhbGwucGFja2FnZXMoImF2IikKI2xpYnJhcnkoZ2lmc2tpKQojbGlicmFyeShhdikKCiMjIG1ha2UgZGF0YWZyYW1lIGZvciBwbG90dGluZwojIyBleHRyYWN0IGRhdGEgZm9yIEdHcGxvdCB2ZXJzaW9uIG9mIHRoaXMKZGZfYW5pbWF0aW9uIDwtIGFzLmRhdGEuZnJhbWUobW9ub2NsZS5vYmplY3QuYWxsQGludF9jb2xEYXRhQGxpc3REYXRhJHJlZHVjZWREaW1zQGxpc3REYXRhW1siVU1BUCJdXSkKIyMgYWRkIHB0IHRvIHRoaXMgZGF0YSBmcmFtZToKcHRfdmFsdWVzIDwtIGFzLmRhdGEuZnJhbWUocHNldWRvdGltZShtb25vY2xlLm9iamVjdC5hbGwsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIpKQpkZl9hbmltYXRpb24gPC0gbWVyZ2UoZGZfYW5pbWF0aW9uLCBwdF92YWx1ZXMsIGJ5PSJyb3cubmFtZXMiKSAKcm93bmFtZXMoZGZfYW5pbWF0aW9uKSA8LSBkZl9hbmltYXRpb24kUm93Lm5hbWVzCmNvbG5hbWVzKGRmX2FuaW1hdGlvbilbNF0gPC0gInB0IgoKIyMgbWFrZSB0aGUgc3RhdGljIHBsb3QKcCA8LSBnZ3Bsb3QoZGZfYW5pbWF0aW9uLCBhZXMoeCA9IERJTVVNQVBfMiwgeSA9IERJTVVNQVBfMSwgY29sb3VyID0gcHQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiMjIHZpZXcgcGxvdApwbG90KHApCgojIyBtYWtlIGFuaW1hdGVkIHBsb3QKIyMgbWFrZSBhIGNhdGVnb3J5IGZvciBhbmltYXRpb24KI2RmX2FuaW1hdGlvbiRncm91cCA8LSBjdXQoZGZfYW5pbWF0aW9uJHB0LCAxNSkKCmFuaW0gPC0gcCArCiAgdHJhbnNpdGlvbl90aW1lKHB0KSArCiAgc2hhZG93X21hcmsoKQoKYW5pbWF0ZShhbmltLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDMsIHVuaXRzID0gImluIiwgcmVzID0gMTUwLCBiZyA9ICd0cmFuc3BhcmVudCcpCgojIyB0byBjaGFuZ2UgdGhlIHJlc29sdXRpb24gLSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80OTA1ODU2Ny9kZWZpbmUtc2l6ZS1mb3ItZ2lmLWNyZWF0ZWQtYnktZ2dhbmltYXRlLWNoYW5nZS1kaW1lbnNpb24tcmVzb2x1dGlvbiAKYGBgClNhdmUgYW5pbWF0aW9uCmBgYHtyfQphbmltX3NhdmUoImFuaW1hdGVkX1VNQVBfdHJhbnNwYXJlbnRfYmcuZ2lmIiwgcGF0aCA9ICIuLi9pbWFnZXNfdG9fZXhwb3J0LyIpCmBgYAoKYGBge3J9CiMjIGV4dHJhY3QgcHQgdmFsdWVzCnB0X3ZhbHVlcyA8LSBhcy5kYXRhLmZyYW1lKHBzZXVkb3RpbWUobW9ub2NsZS5vYmplY3QuYWxsLCByZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiKSkKCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcHRfdmFsdWVzLCAib2xkX3B0X3ZhbHVlcyIpCmBgYAoKbWFrZSBjb21wb3NpdGUgcHNldWRvdGltZS9JRCBmaWd1cmUKCmBgYHtyfQojIDEgPSBibHVlIC0gIiMwMDUyYzUiCiMgMiA9IHJlZCAtICIjYTUyYjFlIgojIDMgPSBncmVlbiAtICIjMDE2YzAwIgojIDQgPSB5ZWxsb3cgLSAiI2ZmZTQwMCIKI3BhbF9zZXggPC0gYygiIzAwNTJjNSIsIiNmZmU0MDAiLCAiI2E1MmIxZSIsICIjMDE2YzAwIikKCiMjIGV4dHJhY3QgcHNlb2R0aW1lIG51bWJlcnMgYW5kIGlkZW50aXR5IG9mIGNlbGxzIHRvIGEgZGF0YWZyYW1lCmRmX3B0X2lkIDwtIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhWyxjKCJvbGRfcHRfdmFsdWVzIiwgImNsdXN0ZXJfY29sb3Vyc19maWd1cmUiKV0KCiMjIGluc3BlY3QgcG9zc2libGUgdmFsdWVzCmxpc3Rfb2Zfc2V4ZXMgPC0gbmFtZXModGFibGUoZGZfcHRfaWQkY2x1c3Rlcl9jb2xvdXJzX2ZpZ3VyZSkpCgojIyBtYWtlIGEgbmV3IGNvbHVtbgpkZl9wdF9pZCRjb2xvdXIgPC0gTkEKCiMjIG1ha2UgY29sb3VyIHJhbXBzCmFzZXhfcmFtcCA8LSBjb2xvclJhbXBQYWxldHRlKGMoIiNENUUzRjUiLCAiIzAwNTJjNSIpKQptYWxlX3JhbXAgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsICJ5ZWxsb3ciLCAiIzAxNmMwMCIpKQpmZW1hbGVfcmFtcCA8LSBjb2xvclJhbXBQYWxldHRlKGMoInllbGxvdyIsICIjYTUyYjFlIikpCmJpcG90X3JhbXAgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGl0ZSIsICIjZmZlNDAwIikpCgojIyByZS1jbGFzc2lmeSBjZWxscyByZW1vdmVkIGZyb20gc2V4dWFsIGJyYW5jaCBhYm92ZToKZGZfcHRfaWRbd2hpY2gocm93bmFtZXMoZGZfcHRfaWQpICVpbiUgcmVtb3ZlX2NlbGxzKSwgXSRjbHVzdGVyX2NvbG91cnNfZmlndXJlIDwtICJBc2V4dWFsIgoKIyMgYXNzaWduIHZhbHVlcyB0byBlYWNoIGNsdXN0ZXIKIyMgaGVscCBoZXJlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy85OTQ2NjMwL2NvbG91ci1wb2ludHMtaW4tYS1wbG90LWRpZmZlcmVudGx5LWRlcGVuZGluZy1vbi1hLXZlY3Rvci1vZi12YWx1ZXMgCmRmX3B0X2lkW2RmX3B0X2lkJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPT0gIkFzZXh1YWwiLCBdJGNvbG91ciA8LSBhc2V4X3JhbXAoMTAwKVthcy5udW1lcmljKGN1dChkZl9wdF9pZFtkZl9wdF9pZCRjbHVzdGVyX2NvbG91cnNfZmlndXJlID09ICJBc2V4dWFsIiwgXSRvbGRfcHRfdmFsdWVzLGJyZWFrcyA9IDEwMCkpXQoKZGZfcHRfaWRbZGZfcHRfaWQkY2x1c3Rlcl9jb2xvdXJzX2ZpZ3VyZSA9PSAiTWFsZSIsIF0kY29sb3VyIDwtIG1hbGVfcmFtcCgxMDApW2FzLm51bWVyaWMoY3V0KGRmX3B0X2lkW2RmX3B0X2lkJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPT0gIk1hbGUiLCBdJG9sZF9wdF92YWx1ZXMsYnJlYWtzID0gMTAwKSldCgpkZl9wdF9pZFtkZl9wdF9pZCRjbHVzdGVyX2NvbG91cnNfZmlndXJlID09ICJGZW1hbGUiLCBdJGNvbG91ciA8LSBmZW1hbGVfcmFtcCgxMDApW2FzLm51bWVyaWMoY3V0KGRmX3B0X2lkW2RmX3B0X2lkJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPT0gIkZlbWFsZSIsIF0kb2xkX3B0X3ZhbHVlcyxicmVha3MgPSAxMDApKV0KCmRmX3B0X2lkW2RmX3B0X2lkJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPT0gIkJpcG90ZW50aWFsIiwgXSRjb2xvdXIgPC0gYmlwb3RfcmFtcCgxMDApW2FzLm51bWVyaWMoY3V0KGRmX3B0X2lkW2RmX3B0X2lkJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPT0gIkJpcG90ZW50aWFsIiwgXSRvbGRfcHRfdmFsdWVzLGJyZWFrcyA9IDEwMCkpXQoKIyMgY2hlY2sgZXZlcnl0aGluZyBoYXMgYSB2YWx1ZQojdGFibGUoaXMubmEoZGZfcHRfaWQkY29sb3VyKSkKCiMjIG1ha2UgaW50byBhIGRmCiNkZl9wdF9pZCA8LSBkZl9wdF9pZFsgLCJjb2xvdXIiLCBkcm9wID0gRkFMU0VdCgojIyBhZGQgYmFjayB0byBzZXVyYXQgb2JqZWN0CmRmIDwtIGRmX3B0X2lkWyAsImNvbG91ciIsIGRyb3AgPSBGQUxTRV0KdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBBZGRNZXRhRGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkZiwgInB0X2lkX2NvbHMiKQpybShkZikKCiMjIHBsb3QKIyMgZXh0cmFjdCBVTUFQIGNvb3JkcwpkZl91bWFwX3Bsb3QgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZEByZWR1Y3Rpb25zW1siRElNX1VNQVAiXV1AY2VsbC5lbWJlZGRpbmdzCmRmX3VtYXBfcGxvdCA8LSBtZXJnZShkZl91bWFwX3Bsb3QsIGRmX3B0X2lkLCBieT0wLCBhbGw9VFJVRSkKCiMjIG1ha2UgZ2dwbG90CnVtYXBfaWRfcHQgPC0gZ2dwbG90KGRmX3VtYXBfcGxvdCwgYWVzKHggPSBESU1VTUFQXzIsIHkgPSBESU1VTUFQXzEpKSArIAogICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGNvbCA9IGRmX3VtYXBfcGxvdCRjb2xvdXIpICsKICAgICAgICAgICAgICAgICAgICAgdGhlbWVfdm9pZCgpICsKICAgICAgICAgICAgICAgICAgICAgY29vcmRfZml4ZWQoKQoKdW1hcF9pZF9wdApgYGAKCmBgYHtyfQp0ZXN0IDwtIGRmX3VtYXBfcGxvdFt3aGljaChkZl91bWFwX3Bsb3QkY2x1c3Rlcl9jb2xvdXJzX2ZpZ3VyZSA9PSAiTWFsZSIpLCBdCmdncGxvdCh0ZXN0LCBhZXMoeCA9IERJTVVNQVBfMiwgeSA9IERJTVVNQVBfMSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV92b2lkKCkKCmBgYAoKCiMgMTAuIFNhdmUgYW5kIEV4cG9ydCB7LnRhYnNldH0KClNhdmUgZW52aXJvbm1lbnQKYGBge3J9CiMjIFRoaXMgc2F2ZXMgZXZlcnl0aGluZyBpbiB0aGUgZ2xvYmFsIGVudmlyb25tZW50IGZvciBlYXN5IHJlY2FsbCBsYXRlcgojc2F2ZS5pbWFnZShmaWxlID0gIkdDU0tPX21lcmdlLlJEYXRhIikKI2xvYWQoZmlsZSA9ICJHQ1NLT19tZXJnZS5SRGF0YSIpCmBgYAoKU2F2ZSBvYmplY3QocykKYGBge3J9CiMjIFNhdmUgYW4gb2JqZWN0IHRvIGEgZmlsZQpzYXZlUkRTKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBmaWxlID0gIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4LlJEUyIpCiMjIFJlc3RvcmUgdGhlIG9iamVjdAojcmVhZFJEUyhmaWxlID0gIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4LlJEUyIpCgojIyBzYXZlIGludGVncmF0ZWQgb2JqZWN0IHRvIGZpbGUKc2F2ZVJEUyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmaWxlID0gIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuUkRTIikgCiMjIHJlc3RvcmUgdGhlIG9iamVjdAojdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSByZWFkUkRTKCIuLi9kYXRhX3RvX2V4cG9ydC90ZW54Lm11dGFudC5pbnRlZ3JhdGVkLlJEUyIpCmBgYAoKIyBBcHBlbmRpeCB7LnRhYnNldH0KCiMjIFNlc3Npb24gSW5mbyAKYGBge3IsIGVjaG8gPSBGQUxTRX0Kc2Vzc2lvbkluZm8oKQpgYGAKCiMjIEV4dHJhcwoKIyMjIFBhcnQgMiBleHBvcnQgZGF0YSBmcmFtZXMgZm9yIEFydGh1cgoKLS0gU3Vic2V0IG9ubHkgMTBYIGNlbGxzCgotLSBjbHVzdGVyIDI0IGlzIHByZWRldGVybWluYXRpb24gY2VsbHMKLS0gY2x1c3RlciAyOSBpcyBwb3N0IGNlbGxzCi0tIGNsdXN0ZXIgMzYgaXMgcG9zdCBjZWxscwpgYGB7cn0KIyMgU3Vic2V0IDEwWCBEYXRhc2V0LCBjbHVzdGVyIDI0CiMjIGV4dHJhY3Qgb25seSBjZWxscyBpbiBjbHVzdGVyIDI0CnNldXJhdC5vYmplY3Quc3Vic2V0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgc3Vic2V0Lm5hbWUgPSAic2V1cmF0X2NsdXN0ZXJzIiwgYWNjZXB0LnZhbHVlID0gYygiMjQiKSkKIyMgZ2V0IHRoZSBuYW1lcyBvZiB0aGUgY2VsbHMgaW4gY2x1c3RlciBvZiBpbnRlcmVzdApuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI0IDwtIGNvbG5hbWVzKHNldXJhdC5vYmplY3Quc3Vic2V0QGFzc2F5cyRSTkFAY291bnRzKQojIyBzdWJzZXQgc2V1cmF0CnRlbnhfY2x1c3Rlcl8yNCA8LSBTdWJzZXREYXRhKHBiX3NleF9maWx0ZXJlZCwgY2VsbHMgPSBuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI0KQojIyBleHRyYWN0IGRhdGEKdGVueF9jbHVzdGVyXzI0X21hdHJpeF9kYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEodGVueF9jbHVzdGVyXzI0LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKSksICdzcGFyc2VNYXRyaXgnKQojIyBleHRyYWN0IGNvdW50cwp0ZW54X2NsdXN0ZXJfMjRfbWF0cml4X2NvdW50cyA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHRlbnhfY2x1c3Rlcl8yNCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJjb3VudHMiKSksICdzcGFyc2VNYXRyaXgnKQojIyBleHRyYWN0IG1ldGEgZGF0YQojIyBtYWtlIGJpZyBtZXRhIGRhdGEgZGF0YWZyYW1lCm1ldGFfZGYgPC0gZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEpCiNtZXRhX2RmIDwtIGRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEpCnRlbnhfY2x1c3Rlcl8yNF9wZCA8LSBtZXRhX2RmW3doaWNoKHJvd25hbWVzKG1ldGFfZGYpICVpbiUgY29sbmFtZXModGVueF9jbHVzdGVyXzI0X21hdHJpeF9jb3VudHMpKSwgXQojIHNhdmUgYWxsIDMgZmlsZXMKI3dyaXRlLmNzdih0ZW54X2NsdXN0ZXJfMjRfbWF0cml4X2RhdGEsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMjRfbWF0cml4X2RhdGEuY3N2IikKI3dyaXRlLmNzdih0ZW54X2NsdXN0ZXJfMjRfbWF0cml4X2NvdW50cywgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3RlbnhfY2x1c3Rlcl8yNF9tYXRyaXhfY291bnRzLmNzdiIpCndyaXRlLmNzdih0ZW54X2NsdXN0ZXJfMjRfcGQsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMjRfcGQuY3N2IikKCiMjIFN1YnNldCAxMFggRGF0YXNldCwgY2x1c3RlciAyOQojIGV4dHJhY3Qgb25seSBjZWxscyBpbiBjbHVzdGVyIDI5CnNldXJhdC5vYmplY3Quc3Vic2V0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgc3Vic2V0Lm5hbWUgPSAic2V1cmF0X2NsdXN0ZXJzIiwgYWNjZXB0LnZhbHVlID0gYygiMjkiKSkKI2dldCB0aGUgbmFtZXMgb2YgdGhlIGNlbGxzIGluIGNsdXN0ZXIgb2YgaW50ZXJlc3QKbmFtZXNfb2ZfY2VsbHNfaW5fY2x1c3Rlcl8yOSA8LSBjb2xuYW1lcyhzZXVyYXQub2JqZWN0LnN1YnNldEBhc3NheXMkUk5BQGNvdW50cykKIyBzdWJzZXQgc2V1cmF0CnRlbnhfY2x1c3Rlcl8yOSA8LSBTdWJzZXREYXRhKHBiX3NleF9maWx0ZXJlZCwgY2VsbHMgPSBuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI5KQojIGV4dHJhY3QgZGF0YQp0ZW54X2NsdXN0ZXJfMjlfbWF0cml4X2RhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YSh0ZW54X2NsdXN0ZXJfMjksIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCiMgZXh0cmFjdCBjb3VudHMKdGVueF9jbHVzdGVyXzI5X21hdHJpeF9jb3VudHMgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YSh0ZW54X2NsdXN0ZXJfMjksIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiY291bnRzIikpLCAnc3BhcnNlTWF0cml4JykKIyBleHRyYWN0IG1ldGEgZGF0YQp0ZW54X2NsdXN0ZXJfMjlfcGQgPC0gbWV0YV9kZlt3aGljaChyb3duYW1lcyhtZXRhX2RmKSAlaW4lIGNvbG5hbWVzKHRlbnhfY2x1c3Rlcl8yOV9tYXRyaXhfY291bnRzKSksIF0KIyBzYXZlIGFsbCAzIGZpbGVzCiN3cml0ZS5jc3YodGVueF9jbHVzdGVyXzI5X21hdHJpeF9kYXRhLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvdGVueF9jbHVzdGVyXzI5X21hdHJpeF9kYXRhLmNzdiIpCiN3cml0ZS5jc3YodGVueF9jbHVzdGVyXzI5X21hdHJpeF9jb3VudHMsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMjlfbWF0cml4X2NvdW50cy5jc3YiKQp3cml0ZS5jc3YodGVueF9jbHVzdGVyXzI5X3BkLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvdGVueF9jbHVzdGVyXzI5X3BkLmNzdiIpCgojIyBTdWJzZXQgMTBYIERhdGFzZXQsIGNsdXN0ZXIgMzYKIyBleHRyYWN0IG9ubHkgY2VsbHMgaW4gY2x1c3RlciAzNgpzZXVyYXQub2JqZWN0LnN1YnNldCA8LSBTdWJzZXREYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQsIHN1YnNldC5uYW1lID0gInNldXJhdF9jbHVzdGVycyIsIGFjY2VwdC52YWx1ZSA9IGMoIjM2IikpCiNnZXQgdGhlIG5hbWVzIG9mIHRoZSBjZWxscyBpbiBjbHVzdGVyIG9mIGludGVyZXN0Cm5hbWVzX29mX2NlbGxzX2luX2NsdXN0ZXJfMzYgPC0gY29sbmFtZXMoc2V1cmF0Lm9iamVjdC5zdWJzZXRAYXNzYXlzJFJOQUBjb3VudHMpCiMgc3Vic2V0IHNldXJhdAp0ZW54X2NsdXN0ZXJfMzYgPC0gU3Vic2V0RGF0YShwYl9zZXhfZmlsdGVyZWQsIGNlbGxzID0gbmFtZXNfb2ZfY2VsbHNfaW5fY2x1c3Rlcl8zNikKIyBleHRyYWN0IGRhdGEKdGVueF9jbHVzdGVyXzM2X21hdHJpeF9kYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEodGVueF9jbHVzdGVyXzM2LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKSksICdzcGFyc2VNYXRyaXgnKQojIGV4dHJhY3QgY291bnRzCnRlbnhfY2x1c3Rlcl8zNl9tYXRyaXhfY291bnRzIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEodGVueF9jbHVzdGVyXzM2LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImNvdW50cyIpKSwgJ3NwYXJzZU1hdHJpeCcpCiMgZXh0cmFjdCBtZXRhIGRhdGEKdGVueF9jbHVzdGVyXzM2X3BkIDwtIG1ldGFfZGZbd2hpY2gocm93bmFtZXMobWV0YV9kZikgJWluJSBjb2xuYW1lcyh0ZW54X2NsdXN0ZXJfMzZfbWF0cml4X2NvdW50cykpLCBdCiMgc2F2ZSBhbGwgMyBmaWxlcwojd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8zNl9tYXRyaXhfZGF0YSwgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3RlbnhfY2x1c3Rlcl8zNl9tYXRyaXhfZGF0YS5jc3YiKQojd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8zNl9tYXRyaXhfY291bnRzLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvdGVueF9jbHVzdGVyXzM2X21hdHJpeF9jb3VudHMuY3N2IikKd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8zNl9wZCwgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3RlbnhfY2x1c3Rlcl8zNl9wZC5jc3YiKQpgYGAKCiMjIyBvbGQgY29kZQoKYGBge3J9CiMjIG9sZCB0aHJlc2hvbGRzIG9uIGRhdGEgd2l0aCAyOAojcmVtb3ZlX2NlbGxzIDwtIHJvdy5uYW1lcyhkZl9zZXhfY2VsbF9lbWJlZGRpbmdzW3doaWNoKGRmX3NleF9jZWxsX2VtYmVkZGluZ3MkRElNVU1BUF8yIDwgMC4xICYgZGZfc2V4X2NlbGxfZW1iZWRkaW5ncyRESU1VTUFQXzEgPiAtMS4yKSwgXSkKYGBgCgojIyMgUHVibGljYXRpb24gRmlndXJlCgpbQ293cGxvdF0oaHR0cHM6Ly93aWxrZWxhYi5vcmcvY293cGxvdC9hcnRpY2xlcy9wbG90X2dyaWQuaHRtbCkocGxvdF9ncmlkKSwgW3BhdGNod29ya10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BhdGNod29yay92aWduZXR0ZXMvcGF0Y2h3b3JrLmh0bWwpKHdyYXBfcGxvdHMpLCBhbmQgW2dncHVicl0oaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC9hcnRpY2xlcy8yNC1nZ3B1YnItcHVibGljYXRpb24tcmVhZHktcGxvdHMvODEtZ2dwbG90Mi1lYXN5LXdheS10by1taXgtbXVsdGlwbGUtZ3JhcGhzLW9uLXRoZS1zYW1lLXBhZ2UvKSBjYW4gYWxsIGFsbG93IG11bHRpcGxlIHBsb3RzIHRvIGJlIHBsb3R0ZWQgdG9nZXRoZXIuIAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMS43LCBmaWcud2lkdGggPSA4LjN9CiMjIEEKIyB1bWFwX2lkX3B0CiMjIEIKIyBtYXJrZXIgZ2VuZSBleHByZXNzaW9uCiMjIEMKIyBNdXRhbnQgZ2VuZSBleHByZXNzaW9uCiMjIEQKIyBNb2R1bGVzCgojRmlndXJlX0EgPC0gZ3JpZC5hcnJhbmdlKGFycmFuZ2VHcm9iKFFDX2NvbXBvc2l0ZV9wbG90LCBRQ19taXRvX3Zpb2xpbiwgUUNfbWl0b19ncmFwaCwgUUNfYnlfZ2Vub3R5cGUsIG1hcHBpbmdfcmF0ZV9wbG90KSwgbnJvdz0zKSwgbnJvdz0yLCBoZWlnaHRzPWMoMTAsMikpCgojIyBjb3dwbG90IG1ldGhvZAojIyBjYW4gdXNlIHRoaXMgZm9yIGxhYmVsczogdG91cHBlcihsZXR0ZXJzKVsxOjEwXQoKIyMgQy4gTXV0YW50IGdlbmVzCm11dGFudF9nZW5lc19maWd1cmUgPC0gcGxvdF9ncmlkKAogICMjIG1hcmtlciBnZW5lcyBzdGFydHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1s4XV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIkZhbS1iMiAoUmluZykiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIGJhcmhlaWdodCA9IDQuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c1tbNV1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NykpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJNU1A4IChBc2V4dWFsKSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gNC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1s0XV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk1TUDEgKFNjaGl6b250KSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gNC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1szXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIkFQMkcgKENvbW1pdG1lbnQpIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSApKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSA0LjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNbWzFdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiQ0NQMiAoRmVtYWxlKSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gNC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzW1syXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk1HMSAoTWFsZSkiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIGJhcmhlaWdodCA9IDQuNSwgdGl0bGUgPSAiIikpLAogICMjIG11dGFudCBnZW5lcyBzdGFydHMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzFdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiZ2QxIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSA0LjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNfbXV0YW50X2dlbmVzW1syXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIm1kMSIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gNC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbM11dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OSkpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJtZDIiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIGJhcmhlaWdodCA9IDQuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzRdXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSArIGxhYnModGl0bGUgPSBwYXN0ZSgibWQzIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSApKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSA0LjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNfbXV0YW50X2dlbmVzW1s1XV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoIm1kNCIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gNC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbNl1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OSkpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJtZDUiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIGJhcmhlaWdodCA9IDQuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzddXSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiZmQxIikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSA0LjUsIHRpdGxlID0gIiIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0X29mX2RlbnNpdHlfcGxvdHNfbXV0YW50X2dlbmVzW1s4XV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkgKyBsYWJzKHRpdGxlID0gcGFzdGUoImZkMiIpKSArIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3Vycz1jKCIjRENEQ0RDIiwgcGxhc21hKDMwKSkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gNC41LCB0aXRsZSA9ICIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdF9vZl9kZW5zaXR5X3Bsb3RzX211dGFudF9nZW5lc1tbOV1dICsgY29vcmRfZml4ZWQoKSArIHRoZW1lX3ZvaWQoKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OSkpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJmZDMiKSkgKyBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9YygiI0RDRENEQyIsIHBsYXNtYSgzMCkpKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAwLjUsIGJhcmhlaWdodCA9IDQuNSwgdGl0bGUgPSAiIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3Rfb2ZfZGVuc2l0eV9wbG90c19tdXRhbnRfZ2VuZXNbWzEwXV0gKyBjb29yZF9maXhlZCgpICsgdGhlbWVfdm9pZCgpKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiZmQ0IikpICsgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvdXJzPWMoIiNEQ0RDREMiLCBwbGFzbWEoMzApKSkgKyBndWlkZXMoY29sb3VyID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSA0LjUsIHRpdGxlID0gIiIpKSwKICBsYWJlbHMgPSBjKHRvdXBwZXIobGV0dGVycylbMjoxN10pLCAKICBsYWJlbF9zaXplID0gMTIsIAogIG5yb3cgPSA0KQoKRmlndXJlX3B1YmxpY2F0aW9uIDwtIHBsb3RfZ3JpZCh1bWFwX2lkX3B0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhbnRfZ2VuZXNfZmlndXJlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIGFkZCBlbXB0eSBwbG90IHRvIGdpdmUgc3BhY2luZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgdGhlbWVfdm9pZCgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoJ0EnKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDEyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdz0yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMSwgMSwgNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsIDIsIDMpKQoKRmlndXJlX3B1YmxpY2F0aW9uCmBgYAoKc2F2ZQpgYGB7cn0KZ2dzYXZlKCIuLi9pbWFnZXNfdG9fZXhwb3J0L0ZpZ3VyZV9DLnBuZyIsIHBsb3QgPSBGaWd1cmVfcHVibGljYXRpb24sIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDIxLCBoZWlnaHQgPSAyOS43LCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgpzYXZlIGFuZCBleHBvcnQgaW5kaXZpZHVhbCBwbG90cyBzbyBpdCBjYW4gYmUgc3RpdGNoZWQgd2l0aCA=